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

Merge branch 'development' of github.com:HaxeFoundation/haxe into development

Nicolas Cannasse 6 жил өмнө
parent
commit
cefe46fac2
100 өөрчлөгдсөн 2975 нэмэгдсэн , 1519 устгасан
  1. 4 0
      .github/FUNDING.yml
  2. 1 0
      .gitignore
  3. 9 0
      .vscode/schemas/define.schema.json
  4. 9 0
      .vscode/schemas/meta.schema.json
  5. 3 7
      Makefile
  6. 7 7
      Makefile.win
  7. 1 1
      README.md
  8. 17 97
      azure-pipelines.yml
  9. 1 1
      extra/azure-pipelines/build-linux.yml
  10. 1 1
      extra/azure-pipelines/build-mac.yml
  11. 4 1
      extra/azure-pipelines/build-windows.yml
  12. 1 1
      extra/azure-pipelines/install-neko-snapshot.yaml
  13. 87 0
      extra/azure-pipelines/test-windows.yml
  14. 1 1
      extra/haxelib_src
  15. 1 1
      extra/installer.nsi
  16. 10 0
      libs/ttflib/tTFData.ml
  17. 2 2
      libs/ttflib/tTFSwfWriter.ml
  18. 1 1
      opam
  19. 144 121
      src-json/define.json
  20. 234 177
      src-json/meta.json
  21. 79 71
      src/codegen/dotnet.ml
  22. 8 8
      src/codegen/gencommon/gencommon.ml
  23. 299 238
      src/codegen/java.ml
  24. 57 28
      src/codegen/swfLoader.ml
  25. 9 29
      src/compiler/displayOutput.ml
  26. 40 46
      src/compiler/main.ml
  27. 20 4
      src/compiler/server.ml
  28. 75 22
      src/context/common.ml
  29. 78 1
      src/context/compilationServer.ml
  30. 9 3
      src/context/display/deprecationCheck.ml
  31. 3 0
      src/context/display/diagnostics.ml
  32. 7 2
      src/context/display/displayEmitter.ml
  33. 95 18
      src/context/display/displayException.ml
  34. 5 2
      src/context/display/displayFields.ml
  35. 14 2
      src/context/display/displayJson.ml
  36. 54 12
      src/context/display/displayToplevel.ml
  37. 1 4
      src/context/display/findReferences.ml
  38. 60 0
      src/context/nativeLibraries.ml
  39. 39 0
      src/context/nativeLibraryHandler.ml
  40. 9 2
      src/context/typecore.ml
  41. 12 2
      src/core/abstract.ml
  42. 9 4
      src/core/define.ml
  43. 35 9
      src/core/display/completionItem.ml
  44. 3 1
      src/core/displayTypes.ml
  45. 3 1
      src/core/error.ml
  46. 1 0
      src/core/globals.ml
  47. 6 1
      src/core/json/genjson.ml
  48. 2 1
      src/core/meta.ml
  49. 142 23
      src/core/type.ml
  50. 15 15
      src/core/withType.ml
  51. 74 22
      src/filters/filters.ml
  52. 1 0
      src/generators/genas3.ml
  53. 122 73
      src/generators/gencpp.ml
  54. 68 59
      src/generators/gencs.ml
  55. 20 12
      src/generators/genhl.ml
  56. 79 71
      src/generators/genjava.ml
  57. 105 47
      src/generators/genjvm.ml
  58. 20 1
      src/generators/genphp7.ml
  59. 1 1
      src/generators/genpy.ml
  60. 23 9
      src/generators/genswf.ml
  61. 7 2
      src/generators/genswf9.ml
  62. 19 0
      src/generators/jvm/jvmAttribute.ml
  63. 19 0
      src/generators/jvm/jvmBuilder.ml
  64. 19 0
      src/generators/jvm/jvmClass.ml
  65. 19 0
      src/generators/jvm/jvmCode.ml
  66. 19 0
      src/generators/jvm/jvmConstantPool.ml
  67. 21 2
      src/generators/jvm/jvmData.ml
  68. 19 0
      src/generators/jvm/jvmDebug.ml
  69. 21 0
      src/generators/jvm/jvmGlobals.ml
  70. 30 11
      src/generators/jvm/jvmMethod.ml
  71. 19 0
      src/generators/jvm/jvmSignature.ml
  72. 19 0
      src/generators/jvm/jvmVerificationTypeInfo.ml
  73. 29 3
      src/generators/jvm/jvmWriter.ml
  74. 30 3
      src/macro/eval/evalContext.ml
  75. 28 11
      src/macro/eval/evalDebugMisc.ml
  76. 2 3
      src/macro/eval/evalMain.ml
  77. 3 3
      src/macro/eval/evalPrototype.ml
  78. 43 14
      src/macro/eval/evalStdLib.ml
  79. 8 13
      src/macro/macroApi.ml
  80. 0 1
      src/optimization/analyzer.ml
  81. 0 2
      src/optimization/analyzerTexprTransformer.ml
  82. 28 13
      src/prebuild/main.ml
  83. 14 6
      src/syntax/grammar.mly
  84. 14 1
      src/syntax/lexer.ml
  85. 2 2
      src/syntax/parser.ml
  86. 14 8
      src/typing/calls.ml
  87. 38 14
      src/typing/fields.ml
  88. 6 1
      src/typing/forLoop.ml
  89. 2 2
      src/typing/macroContext.ml
  90. 11 14
      src/typing/matcher.ml
  91. 26 16
      src/typing/nullSafety.ml
  92. 10 11
      src/typing/typeload.ml
  93. 34 4
      src/typing/typeloadCheck.ml
  94. 10 6
      src/typing/typeloadFields.ml
  95. 1 8
      src/typing/typeloadFunction.ml
  96. 11 5
      src/typing/typeloadModule.ml
  97. 7 3
      src/typing/typeloadParse.ml
  98. 115 57
      src/typing/typer.ml
  99. 1 6
      src/typing/typerBase.ml
  100. 17 11
      src/typing/typerDisplay.ml

+ 4 - 0
.github/FUNDING.yml

@@ -0,0 +1,4 @@
+# These are supported funding model platforms
+
+open_collective: haxe
+custom: ['https://haxe.org/foundation/support-plans.html', 'https://haxe.org/foundation/donate.html']

+ 1 - 0
.gitignore

@@ -127,3 +127,4 @@ tests/benchs/dump/
 tests/display/.unittest/
 tests/unit/.unittest/
 tests/threads/export/
+tests/server/test.js.map

+ 9 - 0
.vscode/schemas/define.schema.json

@@ -48,6 +48,15 @@
 			"devcomment": {
 				"type": "string",
 				"markdownDescription": "Internal comment that is not exposed."
+			},
+			"links": {
+				"type": "array",
+				"markdownDescription": "Relevant URLs.",
+				"minItems": 1,
+				"items": {
+					"type": "string",
+					"format": "uri"
+				}
 			}
 		},
 		"required": [

+ 9 - 0
.vscode/schemas/meta.schema.json

@@ -70,6 +70,15 @@
 						"TAnyField"
 					]
 				}
+			},
+			"links": {
+				"type": "array",
+				"markdownDescription": "Relevant URLs.",
+				"minItems": 1,
+				"items": {
+					"type": "string",
+					"format": "uri"
+				}
 			}
 		},
 		"required": [

+ 3 - 7
Makefile

@@ -123,7 +123,7 @@ build_dirs:
 	@mkdir -p $(BUILD_DIRECTORIES)
 
 _build/src/syntax/grammar.ml:src/syntax/grammar.mly
-	camlp4o -impl $< -o $@
+	camlp5o -impl $< -o $@
 
 _build/src/compiler/version.ml: FORCE
 ifneq ($(ADD_REVISION),0)
@@ -211,7 +211,7 @@ uninstall:
 	rm -rf $(DESTDIR)$(INSTALL_STD_DIR)
 
 opam_install:
-	opam install $(OPAM_LIBS) camlp4 ocamlfind --yes
+	opam install $(OPAM_LIBS) camlp5 ocamlfind --yes
 
 # Dependencies
 
@@ -229,13 +229,9 @@ package_src:
 package_unix:
 	mkdir -p $(PACKAGE_OUT_DIR)
 	rm -rf $(PACKAGE_FILE_NAME) $(PACKAGE_FILE_NAME).tar.gz
-	#delete all content which was generated in _build dir except interfaces
-	find _build/ -type f ! -name '*.cmi' -delete
-	#add ocaml version to the _build dir
-	ocaml -version > _build/ocaml.version
 	# Copy the package contents to $(PACKAGE_FILE_NAME)
 	mkdir -p $(PACKAGE_FILE_NAME)
-	cp -r $(HAXE_OUTPUT) $(HAXELIB_OUTPUT) std extra/LICENSE.txt extra/CONTRIB.txt extra/CHANGES.txt _build $(PACKAGE_FILE_NAME)
+	cp -r $(HAXE_OUTPUT) $(HAXELIB_OUTPUT) std extra/LICENSE.txt extra/CONTRIB.txt extra/CHANGES.txt $(PACKAGE_FILE_NAME)
 	# archive
 	tar -zcf $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_bin.tar.gz $(PACKAGE_FILE_NAME)
 	rm -r $(PACKAGE_FILE_NAME)

+ 7 - 7
Makefile.win

@@ -6,6 +6,11 @@ HAXELIB_OUTPUT=haxelib.exe
 PREBUILD_OUTPUT=prebuild.exe
 EXTENSION=.exe
 PACKAGE_SRC_EXTENSION=.zip
+ARCH?=32
+
+ifeq ($(ARCH),64)
+NEKO_ARCH_STR=64
+endif
 
 kill:
 	-@taskkill /F /IM haxe.exe
@@ -34,10 +39,9 @@ endif
 
 ifdef FILTER
 CC_CMD=($(COMPILER) $(ALL_CFLAGS) -c $< 2>tmp.cmi && $(FILTER)) || ($(FILTER) && exit 1)
-CC_PARSER_CMD=($(COMPILER) -pp camlp4o $(ALL_CFLAGS) -c src/syntax/parser.ml 2>tmp.cmi && $(FILTER)) || ($(FILTER) && exit 1)
 endif
 
-PACKAGE_FILES=$(HAXE_OUTPUT) $(HAXELIB_OUTPUT) std _build "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep zlib1.dll | sed -e 's/^\s*//')" "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libpcre-1.dll | sed -e 's/^\s*//')"
+PACKAGE_FILES=$(HAXE_OUTPUT) $(HAXELIB_OUTPUT) std "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep zlib1.dll | sed -e 's/^\s*//')" "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libpcre-1.dll | sed -e 's/^\s*//')"
 
 echo_package_files:
 	echo $(PACKAGE_FILES)
@@ -45,10 +49,6 @@ echo_package_files:
 package_win:
 	mkdir -p out
 	rm -rf $(PACKAGE_FILE_NAME) $(PACKAGE_FILE_NAME).zip temp.zip
-	#delete all content which was generated in _build dir except interfaces
-	find _build/ -type f ! -name '*.cmi' -delete
-	#add ocaml version to the _build dir
-	ocaml -version > _build/ocaml.version
 	# Copy the package contents to $(PACKAGE_FILE_NAME)
 	# Using poor man's cp (zip then unzip), because cp in cygwin is quite broken
 	mkdir -p $(PACKAGE_FILE_NAME)
@@ -71,7 +71,7 @@ package_choco:
 	rm -rf out/choco
 
 $(INSTALLER_TMP_DIR)/neko-win.zip: $(INSTALLER_TMP_DIR)
-	wget -nv http://nekovm.org/media/neko-2.1.0-win.zip -O installer/neko-win.zip
+	wget -nv https://nekovm.org/media/neko-2.2.0-win$(NEKO_ARCH_STR).zip -O installer/neko-win.zip
 
 package_installer_win: $(INSTALLER_TMP_DIR)/neko-win.zip package_win
 	$(eval OUTFILE := $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_installer.zip)

+ 1 - 1
README.md

@@ -100,7 +100,7 @@ Haxe            | Neko  | SWF |  Python   | HL    | PHP   | Lua  |
 4.0.0-preview.4 |       |        |        | 1.6   |       |      |
 4.0.0-preview.5 |       |        |        | 1.8   |       |      |
 4.0.0-rc.1      |       |        |        | 1.9   |       |      |
-
+4.0.0-rc.3      |       |        |        | 1.10  |       |      |
 
 ## Contributing
 

+ 17 - 97
azure-pipelines.yml

@@ -64,6 +64,8 @@ stages:
             lua:
               TEST: lua
         steps:
+          - checkout: self
+            fetchDepth: 20
           - template: extra/azure-pipelines/install-neko-snapshot.yaml
             parameters:
               platform: linux64
@@ -131,6 +133,8 @@ stages:
             lua:
               TEST: lua
         steps:
+          - checkout: self
+            fetchDepth: 20
           - template: extra/azure-pipelines/install-neko-snapshot.yaml
             parameters:
               platform: mac
@@ -161,78 +165,16 @@ stages:
             workingDirectory: $(Build.SourcesDirectory)/tests
             displayName: Test
 
-      - job: TestWin64
-        dependsOn: BuildWin64
-        pool:
-          vmImage: 'windows-2019'
-        variables:
-          HAXELIB_ROOT: C:/haxelib
-          HAXE_ARCH: 64
-        strategy:
-          matrix:
-            macro:
-              TEST: macro
-            neko:
-              TEST: neko
-            hl:
-              TEST: hl
-            cpp:
-              TEST: cpp
-              HXCPP_COMPILE_CACHE: C:/hxcache
-            java:
-              TEST: java,jvm
-            cs:
-              TEST: cs
-            js:
-              TEST: js
-            # https://github.com/microsoft/azure-pipelines-image-generation/issues/990
-            # php:
-            #   TEST: php
-            # TODO. flash has never been enabled on our AppVeyor builds.
-            # flash:
-            #   TEST: flash9,as3
-            python:
-              TEST: python
-            # TODO. Lua has never been enabled on our AppVeyor builds.
-            # lua:
-            #   TEST: lua
-        steps:
-          - template: extra/azure-pipelines/install-neko-snapshot.yaml
-            parameters:
-              platform: windows
-          - task: DownloadPipelineArtifact@0
-            inputs:
-              artifactName: 'win64Binaries'
-              targetPath: win64Binaries
-          - powershell: |
-              Set-PSDebug -Trace 1
-              7z x win64Binaries/*_bin.zip -owin64Binaries
-              $dir = Get-ChildItem win64Binaries/* -Name -Directory
-              Rename-Item win64Binaries/$dir haxe
-              $dir = '' + ( get-location ) + '\win64Binaries\haxe'
-              dir $dir
-              Set-PSDebug -Trace 0
-              Write-Host "##vso[task.prependpath]$dir"
-            displayName: Setup Haxe
-          - script: haxe -version
-            displayName: Print Haxe version
-          - task: UsePythonVersion@0
-            inputs:
-              versionSpec: '3.7'
-          - powershell: |
-              Set-PSDebug -Trace 1
-              $pypath = python -c "import sys; print(sys.executable)"
-              $py3path = $pypath.replace("python.exe","python3.exe")
-              cmd /c mklink $py3path $pypath
-              python3 -V
-            displayName: "Make Python 3 be available as python3 in the cmdline"
-          - script: |
-              mkdir "$(HAXELIB_ROOT)"
-              haxelib setup "$(HAXELIB_ROOT)"
-            displayName: Setup haxelib
-          - script: haxe RunCi.hxml
-            workingDirectory: $(Build.SourcesDirectory)/tests
-            displayName: Test
+      - template: extra/azure-pipelines/test-windows.yml
+        parameters:
+          name: TestWin64
+          arch: '64'
+
+      - template: extra/azure-pipelines/test-windows.yml
+        parameters:
+          name: TestWin32
+          arch: '32'
+
   - stage: StageDeploy
     condition: and(succeeded(), not(variables['System.PullRequest.PullRequestId']))
     jobs:
@@ -241,6 +183,8 @@ stages:
         pool:
           vmImage: 'ubuntu-16.04'
         steps:
+          - checkout: self
+            fetchDepth: 20
           - task: DownloadPipelineArtifact@0
             inputs:
               artifactName: 'linuxBinaries'
@@ -317,31 +261,7 @@ stages:
               AWS_SECRET_ACCESS_KEY: $(HXBUILDS_AWS_SECRET_ACCESS_KEY)
             condition: and(succeeded(), eq(variables['Build.SourceBranchName'], 'development'))
             displayName: Update "latest"
-          - script: |
-              set -ex
-              haxe --run runci.Indexer $(HXBUILDS_S3ADDR)/haxe/linux64
-              aws s3 cp index.html     $(HXBUILDS_S3ADDR)/haxe/linux64/
-              haxe --run runci.Indexer $(HXBUILDS_S3ADDR)/haxe/mac
-              aws s3 cp index.html     $(HXBUILDS_S3ADDR)/haxe/mac/
-              haxe --run runci.Indexer $(HXBUILDS_S3ADDR)/haxe/windows64
-              aws s3 cp index.html     $(HXBUILDS_S3ADDR)/haxe/windows64/
-              haxe --run runci.Indexer $(HXBUILDS_S3ADDR)/haxe/windows64-installer
-              aws s3 cp index.html     $(HXBUILDS_S3ADDR)/haxe/windows64-installer/
-              haxe --run runci.Indexer $(HXBUILDS_S3ADDR)/haxe/windows64-choco
-              aws s3 cp index.html     $(HXBUILDS_S3ADDR)/haxe/windows64-choco/
-              haxe --run runci.Indexer $(HXBUILDS_S3ADDR)/haxe/windows
-              aws s3 cp index.html     $(HXBUILDS_S3ADDR)/haxe/windows/
-              haxe --run runci.Indexer $(HXBUILDS_S3ADDR)/haxe/windows-installer
-              aws s3 cp index.html     $(HXBUILDS_S3ADDR)/haxe/windows-installer/
-              haxe --run runci.Indexer $(HXBUILDS_S3ADDR)/haxe/windows-choco
-              aws s3 cp index.html     $(HXBUILDS_S3ADDR)/haxe/windows-choco/
-              haxe --run runci.Indexer $(HXBUILDS_S3ADDR)/haxe
-              aws s3 cp index.html     $(HXBUILDS_S3ADDR)/haxe/
-            workingDirectory: $(Build.SourcesDirectory)/tests
-            env:
-              AWS_ACCESS_KEY_ID: $(HXBUILDS_AWS_ACCESS_KEY_ID)
-              AWS_SECRET_ACCESS_KEY: $(HXBUILDS_AWS_SECRET_ACCESS_KEY)
-            displayName: Update indices
+
       - job: ApiHaxeOrg
         condition: and(succeeded(), variables['GHP_USERNAME'], variables['GHP_EMAIL'])
         pool:

+ 1 - 1
extra/azure-pipelines/build-linux.yml

@@ -16,7 +16,7 @@ jobs:
           set -ex
           sudo add-apt-repository ppa:avsm/ppa -y # provides newer version of OCaml and OPAM
           sudo apt-get update -qqy
-          sudo apt-get install -qqy ocaml-nox camlp4-extra opam libpcre3-dev zlib1g-dev libgtk2.0-dev ninja-build
+          sudo apt-get install -qqy ocaml-nox camlp5 opam libpcre3-dev zlib1g-dev libgtk2.0-dev ninja-build
         displayName: Install dependencies
       - template: install-neko-snapshot.yaml
         parameters:

+ 1 - 1
extra/azure-pipelines/build-mac.yml

@@ -14,7 +14,7 @@ jobs:
         submodules: recursive
       - script: |
           set -ex
-          brew update
+          brew update || brew update || brew update
           brew bundle --file=tests/Brewfile --no-upgrade
         displayName: Install dependencies
       - template: install-neko-snapshot.yaml

+ 4 - 1
extra/azure-pipelines/build-windows.yml

@@ -31,7 +31,10 @@ jobs:
         displayName: Install dependencies
       - template: install-neko-snapshot.yaml
         parameters:
-          platform: windows
+          ${{ if eq(parameters.arch, '64') }}:
+            platform: windows64
+          ${{ if eq(parameters.arch, '32') }}:
+            platform: windows
       - powershell: |
           Set-PSDebug -Trace 1
           curl.exe -fsSL -o cygwin-setup.exe --retry 3 $(CYGWIN_SETUP)

+ 1 - 1
extra/azure-pipelines/install-neko-snapshot.yaml

@@ -6,7 +6,7 @@ steps:
     - powershell: |
         Invoke-WebRequest https://build.haxe.org/builds/neko/${{parameters.platform}}/neko_latest.zip -OutFile $(Agent.TempDirectory)/neko_latest.zip
         Expand-Archive $(Agent.TempDirectory)/neko_latest.zip -DestinationPath $(Agent.TempDirectory)
-        $NEKOPATH = Get-ChildItem $(Agent.TempDirectory)/neko-*-win
+        $NEKOPATH = Get-ChildItem $(Agent.TempDirectory)/neko-*-*
         Write-Host "##vso[task.prependpath]$NEKOPATH"
         Write-Host "##vso[task.setvariable variable=NEKOPATH]$NEKOPATH"
       displayName: Install Neko using snapshot from S3

+ 87 - 0
extra/azure-pipelines/test-windows.yml

@@ -0,0 +1,87 @@
+parameters:
+  name: 'TestWindows'
+  vmImage: 'windows-2019'
+  arch: '64' # or '32'
+
+jobs:
+  - job: ${{ parameters.name }}
+    dependsOn: BuildWin${{ parameters.arch }}
+    pool:
+      vmImage: ${{ parameters.vmImage }}
+    variables:
+      HAXELIB_ROOT: C:/haxelib
+    strategy:
+      matrix:
+        # https://github.com/HaxeFoundation/haxe/issues/8600
+        ${{ if eq(parameters.arch, '64') }}:
+          macro:
+            TEST: macro
+        neko:
+          TEST: neko
+        hl:
+          TEST: hl
+        cpp:
+          TEST: cpp
+          HXCPP_COMPILE_CACHE: C:/hxcache
+        java:
+          # https://github.com/HaxeFoundation/haxe/issues/8601
+          ${{ if eq(parameters.arch, '64') }}:
+            TEST: java,jvm
+          ${{ if eq(parameters.arch, '32') }}:
+            TEST: java
+        cs:
+          TEST: cs
+        js:
+          TEST: js
+        php:
+          TEST: php
+        # TODO. flash has never been enabled on our AppVeyor builds.
+        # flash:
+        #   TEST: flash9,as3
+        python:
+          TEST: python
+        # TODO. Lua has never been enabled on our AppVeyor builds.
+        # lua:
+        #   TEST: lua
+    steps:
+      - checkout: self
+        fetchDepth: 20
+      - template: install-neko-snapshot.yaml
+        parameters:
+          ${{ if eq(parameters.arch, '64') }}:
+            platform: windows64
+          ${{ if eq(parameters.arch, '32') }}:
+            platform: windows
+      - task: DownloadPipelineArtifact@0
+        inputs:
+          artifactName: 'win${{ parameters.arch }}Binaries'
+          targetPath: win${{ parameters.arch }}Binaries
+      - powershell: |
+          Set-PSDebug -Trace 1
+          7z x win${{ parameters.arch }}Binaries/*_bin.zip -owin${{ parameters.arch }}Binaries
+          $dir = Get-ChildItem win${{ parameters.arch }}Binaries/* -Name -Directory
+          Rename-Item win${{ parameters.arch }}Binaries/$dir haxe
+          $dir = '' + ( get-location ) + '\win${{ parameters.arch }}Binaries\haxe'
+          dir $dir
+          Set-PSDebug -Trace 0
+          Write-Host "##vso[task.prependpath]$dir"
+        displayName: Setup Haxe
+      - script: haxe -version
+        displayName: Print Haxe version
+      - task: UsePythonVersion@0
+        inputs:
+          versionSpec: '3.7'
+      - powershell: |
+          Set-PSDebug -Trace 1
+          $pypath = python -c "import sys; print(sys.executable)"
+          $py3path = $pypath.replace("python.exe","python3.exe")
+          cmd /c mklink $py3path $pypath
+          python3 -V
+        displayName: "Make Python 3 be available as python3 in the cmdline"
+      - script: |
+          mkdir "$(HAXELIB_ROOT)"
+          haxelib setup "$(HAXELIB_ROOT)"
+        displayName: Setup haxelib
+      - script: haxe RunCi.hxml
+        workingDirectory: $(Build.SourcesDirectory)/tests
+        displayName: Test

+ 1 - 1
extra/haxelib_src

@@ -1 +1 @@
-Subproject commit cdfe34118bd8e993cf5480ce7a26a6bb5b96f285
+Subproject commit 8795d1120c3afb94dda229cab3a60bad42df506d

+ 1 - 1
extra/installer.nsi

@@ -20,7 +20,7 @@
 !define VERLONG "%%VERLONG%%"
 
 ; Define Neko info
-!define NEKO_VERSION "2.1.0"
+!define NEKO_VERSION "2.2.0"
 
 ; Installer details
 VIAddVersionKey "CompanyName" "Haxe Foundation"

+ 10 - 0
libs/ttflib/tTFData.ml

@@ -344,7 +344,17 @@ type ttf = {
 	ttf_kern : kern option;
 }
 
+type ttf_font_weight =
+	| TFWRegular
+	| TFWBold
+
+type ttf_font_posture =
+	| TFPNormal
+	| TFPItalic
+
 type ttf_config = {
 	mutable ttfc_range_str : string;
 	mutable ttfc_font_name : string option;
+	mutable ttfc_font_weight : ttf_font_weight;
+	mutable ttfc_font_posture : ttf_font_posture;
 }

+ 2 - 2
libs/ttflib/tTFSwfWriter.ml

@@ -200,8 +200,8 @@ let to_swf ttf config =
 		font_is_ansi = false;
 		font_wide_offsets = true;
 		font_wide_codes = true;
-		font_is_italic = false;
-		font_is_bold = false;
+		font_is_italic = config.ttfc_font_posture = TFPItalic;
+		font_is_bold = config.ttfc_font_weight = TFWBold;
 		font_language = LCNone;
 		font_name = (match config.ttfc_font_name with Some s -> s | None -> ttf.ttf_font_name);
 		font_glyphs = glyfs;

+ 1 - 1
opam

@@ -21,7 +21,7 @@ remove: [make "uninstall" "INSTALL_DIR=%{prefix}%"]
 depends: [
   "ocaml"               {>= "4.02"}
   "ocamlfind"           {build}
-  "camlp4"              {build}
+  "camlp5"              {build}
   "sedlex"              {build & <= "1.99.4"} #https://github.com/HaxeFoundation/haxe/issues/7958
   "ppx_tools_versioned" {build & != "5.2.1"} #https://github.com/alainfrisch/sedlex/issues/64
   "xml-light"           {build}

+ 144 - 121
src-json/define.json

@@ -2,148 +2,154 @@
 	{
 		"name": "AbsolutePath",
 		"define": "absolute_path",
-		"doc": "Print absolute file path in trace output"
+		"doc": "Print absolute file path in trace output."
 	},
 	{
 		"name": "AdvancedTelemetry",
 		"define": "advanced-telemetry",
-		"doc": "Allow the SWF to be measured with Monocle tool",
+		"doc": "Allow the SWF to be measured with Monocle tool.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "AnnotateSource",
 		"define": "annotate_source",
-		"doc": "Add additional comments to generated source code",
+		"doc": "Add additional comments to generated source code.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "As3",
 		"define": "as3",
-		"doc": "Defined when outputting flash9 as3 source code"
+		"doc": "Defined when outputting flash9 as3 source code."
 	},
 	{
 		"name": "CheckXmlProxy",
 		"define": "check_xml_proxy",
-		"doc": "Check the used fields of the xml proxy"
+		"doc": "Check the used fields of the XML proxy."
 	},
 	{
 		"name": "CoreApi",
 		"define": "core_api",
-		"doc": "Defined in the core api context"
+		"doc": "Defined in the core API context."
 	},
 	{
 		"name": "CoreApiSerialize",
 		"define": "core_api_serialize",
-		"doc": "Mark some generated core api classes with the Serializable attribute on C#",
+		"doc": "Mark some generated core API classes with the `Serializable` attribute on C#.",
 		"platforms": ["cs"]
 	},
 	{
 		"name": "Cppia",
 		"define": "cppia",
-		"doc": "Generate cpp instruction assembly"
+		"doc": "Generate cpp instruction assembly."
 	},
 	{
 		"name": "CsVer",
 		"define": "cs_ver",
-		"doc": "The C# version to target",
+		"doc": "The C# version to target.",
 		"platforms": ["cs"]
 	},
 	{
 		"name": "NoCppiaAst",
 		"define": "nocppiaast",
-		"doc": "Use legacy cppia generation"
+		"doc": "Use legacy cppia generation."
 	},
 	{
 		"name": "Dce",
 		"define": "dce",
-		"doc": "<mode:std|full|no> Set the dead code elimination mode (default std)"
+		"doc": "Set the dead code elimination mode. (default: std)",
+		"params": ["mode: std | full | no"],
+		"links": ["https://haxe.org/manual/cr-dce.html"]
 	},
 	{
 		"name": "DceDebug",
 		"define": "dce_debug",
-		"doc": "Show DCE log"
+		"doc": "Show DCE log.",
+		"links": ["https://haxe.org/manual/cr-dce.html"]
 	},
 	{
 		"name": "Debug",
 		"define": "debug",
-		"doc": "Activated when compiling with -debug"
+		"doc": "Activated when compiling with -debug."
 	},
 	{
 		"name": "DisableUnicodeStrings",
 		"define": "disable_unicode_strings",
-		"doc": "Disable unicode support in String type on some platforms",
+		"doc": "Disable Unicode support in `String` type.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "Display",
 		"define": "display",
-		"doc": "Activated during completion"
+		"doc": "Activated during completion.",
+		"links": ["https://haxe.org/manual/cr-completion.html"]
 	},
 	{
 		"name": "DisplayStdin",
 		"define": "display_stdin",
-		"doc": "Read the contents of a file specified in --display from standard input"
+		"doc": "Read the contents of a file specified in `--display` from standard input."
 	},
 	{
 		"name": "DllExport",
 		"define": "dll_export",
-		"doc": "GenCPP experimental linking",
+		"doc": "GenCPP experimental linking.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "DllImport",
 		"define": "dll_import",
-		"doc": "Handle Haxe-generated .NET dll imports",
+		"doc": "Handle Haxe-generated .NET DLL imports.",
 		"platforms": ["cs"]
 	},
 	{
 		"name": "DocGen",
 		"define": "doc_gen",
-		"doc": "Do not perform any removal/change in order to correctly generate documentation"
+		"doc": "Do not perform any removal/change in order to correctly generate documentation."
 	},
 	{
 		"name": "Dump",
 		"define": "dump",
-		"doc": "<mode:pretty|record|position|legacy> Dump typed AST in dump subdirectory using specified mode or non-prettified default"
+		"doc": "Dump typed AST in dump subdirectory using specified mode or non-prettified default.",
+		"params": ["mode: pretty | record | position | legacy"]
 	},
 	{
 		"name": "DumpDependencies",
 		"define": "dump_dependencies",
-		"doc": "Dump the classes dependencies in a dump subdirectory"
+		"doc": "Dump the classes dependencies in a dump subdirectory."
 	},
 	{
 		"name": "DumpIgnoreVarIds",
 		"define": "dump_ignore_var_ids",
-		"doc": "Remove variable IDs from non-pretty dumps (helps with diff)"
+		"doc": "Remove variable IDs from non-pretty dumps (helps with diff)."
 	},
 	{
 		"name": "DynamicInterfaceClosures",
 		"define": "dynamic_interface_closures",
-		"doc": "Use slow path for interface closures to save space",
+		"doc": "Use slow path for interface closures to save space.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "EraseGenerics",
 		"define": "erase_generics",
-		"doc": "Erase generic classes on C#",
+		"doc": "Erase generic classes on C#.",
 		"platforms": ["cs"]
 	},
 	{
 		"name": "EvalCallStackDepth",
 		"define": "eval_call_stack_depth",
-		"doc": "Set maximum call stack depth for eval. Default: 1000.",
-		"platforms": ["eval"]
+		"doc": "Set maximum call stack depth for eval. (default: 1000)",
+		"platforms": ["eval"],
+		"params": ["depth"]
 	},
 	{
 		"name": "EvalDebugger",
 		"define": "eval_debugger",
-		"doc": "Support debugger in macro/interp mode. Allows host:port value to open a socket. Implies eval_stack.",
+		"doc": "Support debugger in macro/interp mode. Allows `host:port` value to open a socket. Implies eval_stack.",
 		"platforms": ["eval"]
 	},
 	{
 		"name": "EvalStack",
 		"define": "eval_stack",
-		"doc": "Record stack information in macro/interp mode",
+		"doc": "Record stack information in macro/interp mode.",
 		"platforms": ["eval"]
 	},
 	{
@@ -155,301 +161,310 @@
 	{
 		"name": "FastCast",
 		"define": "fast_cast",
-		"doc": "Enables an experimental casts cleanup on C# and Java",
+		"doc": "Enables an experimental casts cleanup on C# and Java.",
 		"platforms": ["cs", "java"]
 	},
 	{
 		"name": "Fdb",
 		"define": "fdb",
-		"doc": "Enable full flash debug infos for FDB interactive debugging",
+		"doc": "Enable full flash debug infos for FDB interactive debugging.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "FileExtension",
 		"define": "file_extension",
-		"doc": "Output filename extension for cpp source code",
+		"doc": "Output filename extension for cpp source code.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "FlashStrict",
 		"define": "flash_strict",
-		"doc": "More strict typing for flash target",
+		"doc": "More strict typing for flash target.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "FlashUseStage",
 		"define": "flash_use_stage",
-		"doc": "Keep the SWF library initial stage",
+		"doc": "Keep the SWF library initial stage.",
 		"platforms": ["flash"]
 	},
 	{
 		"devcomment": "force_lib_check is only here as a debug facility - compiler checking allows errors to be found more easily",
 		"name": "ForceLibCheck",
 		"define": "force_lib_check",
-		"doc": "Force the compiler to check -net-lib and -java-lib added classes (internal)",
+		"doc": "Force the compiler to check `--net-lib` and `–-java-lib` added classes (internal).",
 		"platforms": ["cs", "java"]
 	},
 	{
 		"name": "ForceNativeProperty",
 		"define": "force_native_property",
-		"doc": "Tag all properties with :nativeProperty metadata for 3.1 compatibility",
+		"doc": "Tag all properties with `:nativeProperty` metadata for 3.1 compatibility.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "GencommonDebug",
 		"define": "gencommon_debug",
-		"doc": "GenCommon internal",
+		"doc": "GenCommon internal.",
 		"platforms": ["cs", "java"]
 	},
 	{
 		"name": "Haxe3Compat",
 		"define": "haxe3compat",
-		"doc": "Gives warnings about transition from Haxe 3.x to Haxe 4.0"
+		"doc": "Gives warnings about transition from Haxe 3.x to Haxe 4.0."
 	},
 	{
 		"name": "HaxeBoot",
 		"define": "haxe_boot",
-		"doc": "Given the name 'haxe' to the flash boot class instead of a generated name",
+		"doc": "Give the name 'haxe' to the flash boot class instead of a generated name.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "HaxeVer",
 		"define": "haxe_ver",
-		"doc": "The current Haxe version value as decimal number. E.g. 4.000 for 4.0.0"
+		"doc": "The current Haxe version value as decimal number. E.g. 3.407 for 3.4.7."
 	},
 	{
 		"name": "Haxe",
 		"define": "haxe",
-		"doc": "The current Haxe version value in SemVer format"
+		"doc": "The current Haxe version value in SemVer format."
 	},
 	{
 		"name": "HxcppApiLevel",
 		"define": "hxcpp_api_level",
-		"doc": "Provided to allow compatibility between hxcpp versions",
+		"doc": "Provided to allow compatibility between hxcpp versions.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "HxcppGcGenerational",
-		"define": "HXCPP_GC_GENERATIONAL",
-		"doc": "Experimental Garbage Collector",
+		"define": "hxcpp_gc_generational",
+		"doc": "Experimental Garbage Collector.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "HxcppDebugger",
-		"define": "HXCPP_DEBUGGER",
-		"doc": "Include additional information for HXCPP_DEBUGGER",
+		"define": "hxcpp_debugger",
+		"doc": "Include additional information for hxcpp_debugger.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "HxcppSmartStings",
 		"define": "hxcpp_smart_strings",
-		"doc": "Use wide strings in hxcpp (Turned on by default unless `-D disable_unicode_strings` is specified)",
+		"doc": "Use wide strings in hxcpp. (Turned on by default unless `-D disable_unicode_strings` is specified.)",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "IncludePrefix",
 		"define": "include_prefix",
-		"doc": "prepend path to generated include files",
+		"doc": "Prepend path to generated include files.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "Interp",
 		"define": "interp",
-		"doc": "The code is compiled to be run with --interp"
+		"doc": "The code is compiled to be run with `--interp`."
 	},
 	{
 		"name": "JavaVer",
 		"define": "java_ver",
-		"doc": "<version:5-7> Sets the Java version to be targeted",
-		"platforms": ["java"]
+		"doc": "Sets the Java version to be targeted.",
+		"platforms": ["java"],
+		"params": ["version: 5-7"]
 	},
 	{
 		"name": "JsClassic",
 		"define": "js_classic",
-		"doc": "Don't use a function wrapper and strict mode in JS output",
+		"doc": "Don't use a function wrapper and strict mode in JS output.",
 		"platforms": ["js"]
 	},
 	{
 		"name": "JsEs",
 		"define": "js_es",
-		"doc": "Generate JS compliant with given ES standard version (default 5)",
+		"doc": "Generate JS compliant with given ES standard version. (default: 5)",
 		"platforms": ["js"],
-		"params": ["version number"]
+		"params": ["version number"],
+		"links": ["https://haxe.org/manual/target-javascript-es6.html"]
 	},
 	{
 		"name": "JsEnumsAsArrays",
 		"define": "js_enums_as_arrays",
-		"doc": "Generate enum representation as array instead of as object",
+		"doc": "Generate enum representation as array instead of as object.",
 		"platforms": ["js"]
 	},
 	{
 		"name": "JsUnflatten",
 		"define": "js_unflatten",
-		"doc": "Generate nested objects for packages and types",
+		"doc": "Generate nested objects for packages and types.",
 		"platforms": ["js"]
 	},
 	{
 		"name": "JsSourceMap",
 		"define": "js_source_map",
-		"doc": "Generate JavaScript source map even in non-debug mode",
+		"doc": "Generate JavaScript source map even in non-debug mode.",
 		"platforms": ["js"]
 	},
 	{
 		"name": "Jvm",
 		"define": "jvm",
-		"doc": "Generate jvm directly",
+		"doc": "Generate jvm directly.",
 		"platforms": ["java"]
 	},
 	{
 		"name": "SourceMap",
 		"define": "source_map",
-		"doc": "Generate source map for compiled files (Currently supported for php only)",
+		"doc": "Generate source map for compiled files.",
 		"platforms": ["php"]
 	},
 	{
 		"name": "KeepOldOutput",
 		"define": "keep_old_output",
-		"doc": "Keep old source files in the output directory",
+		"doc": "Keep old source files in the output directory.",
 		"platforms": ["cs", "java"]
 	},
 	{
 		"name": "LoopUnrollMaxCost",
 		"define": "loop_unroll_max_cost",
-		"doc": "Maximum cost (number of expressions * iterations) before loop unrolling is canceled (default 250)"
+		"doc": "Maximum cost (number of expressions * iterations) before loop unrolling is canceled. (default: 250)",
+		"params": ["cost"]
 	},
 	{
 		"name": "LuaJit",
 		"define": "lua_jit",
-		"doc": "Enable the jit compiler for lua (version 5.2 only)",
+		"doc": "Enable the jit compiler for lua (version 5.2 only).",
 		"platforms": ["lua"]
 	},
 	{
 		"name": "LuaVanilla",
 		"define": "lua_vanilla",
-		"doc": "Generate code lacking compiled extern lib support (e.g. utf8)",
+		"doc": "Generate code lacking compiled extern lib support (e.g. utf8).",
 		"platforms": ["lua"]
 	},
 	{
 		"name": "LuaVer",
 		"define": "lua_ver",
-		"doc": "The lua version to target",
-		"platforms": ["lua"]
+		"doc": "The lua version to target.",
+		"platforms": ["lua"],
+		"params": ["version"]
 	},
 	{
 		"name": "Macro",
 		"define": "macro",
-		"doc": "Defined when code is compiled in the macro context"
+		"doc": "Defined when code is compiled in the macro context.",
+		"links": ["https://haxe.org/manual/macro.html"]
 	},
 	{
 		"name": "MacroTimes",
 		"define": "macro_times",
-		"doc": "Display per-macro timing when used with --times"
+		"doc": "Display per-macro timing when used with `--times`."
 	},
 	{
 		"name": "NetVer",
 		"define": "net_ver",
-		"doc": "<version:20-45> Sets the .NET version to be targeted",
-		"platforms": ["cs"]
+		"doc": "Sets the .NET version to be targeted.",
+		"platforms": ["cs"],
+		"params": ["version: 20-45"]
 	},
 	{
 		"name": "NetcoreVer",
 		"define": "netcore_ver",
-		"doc": "<version:x.x.x> Sets the .NET core version to be targeted",
-		"platforms": ["cs"]
+		"doc": "Sets the .NET core version to be targeted",
+		"platforms": ["cs"],
+		"params": ["version: x.x.x"]
 	},
 	{
 		"name": "NetTarget",
 		"define": "net_target",
-		"doc": "<name> Sets the .NET target. Defaults to \"net\". netcore, xbox, micro (Micro Framework), compact (Compact Framework) are some valid values",
-		"platforms": ["cs"]
+		"doc": "Sets the .NET target. `netcore` (.NET core), `xbox`, `micro` (Micro Framework), `compact` (Compact Framework) are some valid values. (default: `net`)",
+		"platforms": ["cs"],
+		"params": ["name"]
 	},
 	{
 		"name": "NekoSource",
 		"define": "neko_source",
-		"doc": "Output neko source instead of bytecode",
+		"doc": "Output neko source instead of bytecode.",
 		"platforms": ["neko"]
 	},
 	{
 		"name": "NekoV1",
 		"define": "neko_v1",
-		"doc": "Keep Neko 1.x compatibility",
+		"doc": "Keep Neko 1.x compatibility.",
 		"platforms": ["neko"]
 	},
 	{
 		"name": "NetworkSandbox",
 		"define": "network-sandbox",
-		"doc": "Use local network sandbox instead of local file access one",
+		"doc": "Use local network sandbox instead of local file access one.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "NoCompilation",
 		"define": "no-compilation",
-		"doc": "Disable final compilation",
+		"doc": "Disable final compilation.",
 		"platforms": ["cs", "java", "cpp", "hl"]
 	},
 	{
 		"name": "NoCOpt",
 		"define": "no_copt",
-		"doc": "Disable completion optimization (for debug purposes)"
+		"doc": "Disable completion optimization (for debug purposes)."
 	},
 	{
 		"name": "NoDebug",
 		"define": "no_debug",
-		"doc": "Remove all debug macros from cpp output"
+		"doc": "Remove all debug macros from cpp output."
 	},
 	{
 		"name": "NoDeprecationWarnings",
 		"define": "no-deprecation-warnings",
-		"doc": "Do not warn if fields annotated with @:deprecated are used"
+		"doc": "Do not warn if fields annotated with `@:deprecated` are used."
 	},
 	{
 		"name": "NoFlashOverride",
 		"define": "no-flash-override",
-		"doc": "Change overrides on some basic classes into HX suffixed methods, flash only",
+		"doc": "Change overrides on some basic classes into HX suffixed methods",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "NoOpt",
 		"define": "no_opt",
-		"doc": "Disable optimizations"
+		"doc": "Disable optimizations."
 	},
 	{
 		"name": "NoInline",
 		"define": "no_inline",
-		"doc": "Disable inlining"
+		"doc": "Disable inlining.",
+		"links": ["https://haxe.org/manual/class-field-inline.html"]
 	},
 	{
 		"name": "NoRoot",
 		"define": "no_root",
-		"doc": "Generate top-level types into haxe.root namespace",
+		"doc": "Generate top-level types into the `haxe.root` namespace.",
 		"platforms": ["cs"]
 	},
 	{
 		"name": "NoMacroCache",
 		"define": "no_macro_cache",
-		"doc": "Disable macro context caching"
+		"doc": "Disable macro context caching."
 	},
 	{
 		"name": "NoSwfCompress",
 		"define": "no_swf_compress",
-		"doc": "Disable SWF output compression",
+		"doc": "Disable SWF output compression.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "NoTraces",
 		"define": "no_traces",
-		"doc": "Disable all trace calls"
+		"doc": "Disable all trace calls."
 	},
 	{
 		"name": "Objc",
 		"define": "objc",
-		"doc": "Sets the hxcpp output to objective-c++ classes. Must be defined for interop",
+		"doc": "Sets the hxcpp output to Objective-C++ classes. Must be defined for interop.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "OldConstructorInline",
 		"define": "old-constructor-inline",
-		"doc": "Use old constructor inlining logic (from haxe 3.4.2) instead of the reworked version."
+		"doc": "Use old constructor inlining logic (from Haxe 3.4.2) instead of the reworked version."
 	},
 	{
 		"name": "OldErrorFormat",
@@ -460,157 +475,165 @@
 		"name": "PhpPrefix",
 		"define": "php_prefix",
 		"doc": "Root namespace for generated php classes. E.g. if compiled with`-D php-prefix=some.sub`, then all classes will be generated in `\\some\\sub` namespace.",
-		"platforms": ["php"]
+		"platforms": ["php"],
+		"params": ["dot-separated namespace"]
 	},
 	{
 		"name": "PhpLib",
 		"define": "php_lib",
 		"doc": "Select the name for the php lib folder.",
-		"platforms": ["php"]
+		"platforms": ["php"],
+		"params": ["folder name"]
 	},
 	{
 		"name": "PhpFront",
 		"define": "php_front",
-		"doc": "Select the name for the php front file (by default: `index.php`).",
-		"platforms": ["php"]
+		"doc": "Select the name for the php front file. (default: `index.php`)",
+		"platforms": ["php"],
+		"params": ["filename"]
 	},
 	{
 		"name": "PythonVersion",
 		"define": "python_version",
-		"doc": "The python version to target (default 3.3)",
-		"platforms": ["python"]
+		"doc": "The python version to target. (default: 3.3)",
+		"platforms": ["python"],
+		"params": ["version"]
 	},
 	{
 		"name": "RealPosition",
 		"define": "real_position",
-		"doc": "Disables Haxe source mapping when targetting C#, removes position comments in Java and Php output",
+		"doc": "Disables Haxe source mapping when targetting C#, removes position comments in Java and Php output.",
 		"platforms": ["cs", "java", "php"]
 	},
 	{
 		"name": "ReplaceFiles",
 		"define": "replace_files",
-		"doc": "GenCommon internal",
+		"doc": "GenCommon internal.",
 		"platforms": ["cs", "java"]
 	},
 	{
 		"name": "Scriptable",
 		"define": "scriptable",
-		"doc": "GenCPP internal",
+		"doc": "GenCPP internal.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "ShallowExpose",
 		"define": "shallow-expose",
-		"doc": "Expose types to surrounding scope of Haxe generated closure without writing to window object",
+		"doc": "Expose types to surrounding scope of Haxe generated closure without writing to window object.",
 		"platforms": ["js"]
 	},
 	{
 		"name": "SourceHeader",
 		"define": "source-header",
-		"doc": "Print value as comment on top of generated files, use '' value to disable"
+		"doc": "Print value as comment on top of generated files, use '' value to disable."
 	},
 	{
 		"name": "SourceMapContent",
 		"define": "source-map-content",
-		"doc": "Include the hx sources as part of the JS source map",
+		"doc": "Include the Haxe sources as part of the JS source map.",
 		"platforms": ["js"]
 	},
 	{
 		"name": "Static",
 		"define": "static",
-		"doc": "Defined if the current target is static"
+		"doc": "Defined if the current target is static."
 	},
 	{
 		"name": "Swc",
 		"define": "swc",
-		"doc": "Output a SWC instead of a SWF",
+		"doc": "Output a SWC instead of a SWF.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "SwfCompressLevel",
 		"define": "swf_compress_level",
-		"doc": "<level:1-9> Set the amount of compression for the SWF output",
-		"platforms": ["flash"]
+		"doc": "Set the amount of compression for the SWF output.",
+		"platforms": ["flash"],
+		"params": ["level: 1-9"]
 	},
 	{
 		"name": "SwfDebugPassword",
 		"define": "swf_debug_password",
-		"doc": "Set a password for debugging",
-		"platforms": ["flash"]
+		"doc": "Set a password for debugging.",
+		"platforms": ["flash"],
+		"params": ["password"]
 	},
 	{
 		"name": "SwfDirectBlit",
 		"define": "swf_direct_blit",
-		"doc": "Use hardware acceleration to blit graphics",
+		"doc": "Use hardware acceleration to blit graphics.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "SwfGpu",
 		"define": "swf_gpu",
-		"doc": "Use GPU compositing features when drawing graphics",
+		"doc": "Use GPU compositing features when drawing graphics.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "SwfMetadata",
 		"define": "swf_metadata",
-		"doc": "<file> Include contents of <file> as metadata in the swf",
-		"platforms": ["flash"]
+		"doc": "Include contents of the given file as metadata in the SWF.",
+		"platforms": ["flash"],
+		"params": ["file"]
 	},
 	{
 		"name": "SwfPreloaderFrame",
 		"define": "swf_preloader_frame",
-		"doc": "Insert empty first frame in swf",
+		"doc": "Insert empty first frame in SWF.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "SwfProtected",
 		"define": "swf_protected",
-		"doc": "Compile Haxe private as protected in the SWF instead of public",
+		"doc": "Compile Haxe `private` as `protected` in the SWF instead of `public`.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "SwfScriptTimeout",
 		"define": "swf_script_timeout",
-		"doc": "Maximum ActionScript processing time before script stuck dialog box displays (in seconds)",
-		"platforms": ["flash"]
+		"doc": "Maximum ActionScript processing time before script stuck dialog box displays.",
+		"platforms": ["flash"],
+		"params": ["time in seconds"]
 	},
 	{
 		"name": "SwfUseDoAbc",
 		"define": "swf_use_doabc",
-		"doc": "Use DoAbc swf-tag instead of DoAbcDefine",
+		"doc": "Use `DoAbc` SWF-tag instead of `DoAbcDefine`.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "Sys",
 		"define": "sys",
-		"doc": "Defined for all system platforms"
+		"doc": "Defined for all system platforms."
 	},
 	{
 		"name": "Unsafe",
 		"define": "unsafe",
-		"doc": "Allow unsafe code when targeting C#",
+		"doc": "Allow unsafe code when targeting C#.",
 		"platforms": ["cs"]
 	},
 	{
 		"name": "UseNekoc",
 		"define": "use_nekoc",
-		"doc": "Use nekoc compiler instead of internal one",
+		"doc": "Use `nekoc` compiler instead of the internal one.",
 		"platforms": ["neko"]
 	},
 	{
 		"name": "Utf16",
 		"define": "utf16",
-		"doc": "Defined for all platforms that have utf16 encoding with ucs2 api"
+		"doc": "Defined for all platforms that use UTF-16 string encoding with UCS-2 API."
 	},
 	{
 		"name": "Vcproj",
 		"define": "vcproj",
-		"doc": "GenCPP internal",
+		"doc": "GenCPP internal.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "WarnVarShadowing",
 		"define": "warn_var_shadowing",
-		"doc": "Warn about shadowing variable declarations"
+		"doc": "Warn about shadowing variable declarations."
 	}
 ]

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 234 - 177
src-json/meta.json


+ 79 - 71
src/codegen/dotnet.ml

@@ -22,6 +22,7 @@ open Globals
 open Ast
 open IlData
 open IlMeta
+open NativeLibraries
 
 (* see http://msdn.microsoft.com/en-us/library/2sk3x8a7(v=vs.71).aspx *)
 let cs_binops =
@@ -126,11 +127,11 @@ let netpath_to_hx std = function
 
 let lookup_ilclass std com ilpath =
 	let path = netpath_to_hx std ilpath in
-	List.fold_right (fun (_,_,_,get_raw_class) acc ->
+	List.fold_right (fun net_lib acc ->
 		match acc with
-		| None -> get_raw_class path
+		| None -> net_lib#lookup path
 		| Some p -> acc
-	) com.net_libs None
+	) com.native_libs.net_libs None
 
 let discard_nested = function
 	| (ns,_),cl -> (ns,[]),cl
@@ -495,7 +496,7 @@ let convert_ilmethod ctx p m is_explicit_impl =
 			| Some ilcls when not (List.mem SInterface ilcls.cflags.tdf_semantics) ->
 				(AOverride,null_pos) :: acc
 			| None when ctx.ncom.verbose ->
-				prerr_endline ("(net-lib) A referenced assembly for path " ^ ilpath_s path ^ " was not found");
+				print_endline ("(net-lib) A referenced assembly for path " ^ ilpath_s path ^ " was not found");
 				acc
 			| _ -> acc
 	in
@@ -1109,52 +1110,57 @@ let normalize_ilcls ctx cls =
 let add_net_std com file =
 	com.net_std <- file :: com.net_std
 
-let add_net_lib com file std =
-	let ilctx = ref None in
-	let netpath_to_hx = netpath_to_hx std in
-	let real_file = ref file in
-	let get_ctx () =
-		match !ilctx with
-		| Some c ->
-			c
-		| None ->
-			let file = if Sys.file_exists file then
-				file
-			else try Common.find_file com file with
-				| Not_found -> try Common.find_file com (file ^ ".dll") with
-				| Not_found ->
-					failwith (".NET lib " ^ file ^ " not found")
-			in
-			real_file := file;
-			let r = PeReader.create_r (open_in_bin file) com.defines.Define.values in
-			let ctx = PeReader.read r in
-			let clr_header = PeReader.read_clr_header ctx in
-			let cache = IlMetaReader.create_cache () in
-			let meta = IlMetaReader.read_meta_tables ctx clr_header cache in
-			close_in (r.PeReader.ch);
+class net_library com name file_path std = object(self)
+	inherit [net_lib_type,unit] native_library name file_path
+
+	val mutable ilctx = None
+	val cache = Hashtbl.create 0
+
+	method private netpath_to_hx =
+		netpath_to_hx std
+
+	method load =
+		let r = PeReader.create_r (open_in_bin file_path) com.defines.Define.values in
+		let ctx = PeReader.read r in
+		let clr_header = PeReader.read_clr_header ctx in
+		let cache = IlMetaReader.create_cache () in
+		let meta = IlMetaReader.read_meta_tables ctx clr_header cache in
+		close_in (r.PeReader.ch);
+		if PMap.mem "net_loader_debug" com.defines.Define.values then
+			print_endline ("for lib " ^ file_path);
+		let il_typedefs = Hashtbl.copy meta.il_typedefs in
+		Hashtbl.clear meta.il_typedefs;
+
+		Hashtbl.iter (fun _ td ->
+			let path = IlMetaTools.get_path (TypeDef td) in
 			if PMap.mem "net_loader_debug" com.defines.Define.values then
-				print_endline ("for lib " ^ file);
-			let il_typedefs = Hashtbl.copy meta.il_typedefs in
-			Hashtbl.clear meta.il_typedefs;
-
-			Hashtbl.iter (fun _ td ->
-				let path = IlMetaTools.get_path (TypeDef td) in
-				if PMap.mem "net_loader_debug" com.defines.Define.values then
-					Printf.printf "found %s\n" (s_type_path (netpath_to_hx path));
-				Hashtbl.replace com.net_path_map (netpath_to_hx path) path;
-				Hashtbl.replace meta.il_typedefs path td
-			) il_typedefs;
-			let meta = { nstd = std; ncom = com; nil = meta } in
-			ilctx := Some meta;
-			meta
-	in
+				Printf.printf "found %s\n" (s_type_path (self#netpath_to_hx path));
+			Hashtbl.replace com.net_path_map (self#netpath_to_hx path) path;
+			Hashtbl.replace meta.il_typedefs path td
+		) il_typedefs;
+		let meta = { nstd = std; ncom = com; nil = meta } in
+		ilctx <- Some meta
+
+	method get_ctx = match ilctx with
+		| None ->
+			self#load;
+			self#get_ctx
+		| Some ctx ->
+			ctx
+
+	method close =
+		()
 
-	let cache = Hashtbl.create 0 in
-	let lookup path =
+	method list_modules =
+		Hashtbl.fold (fun path _ acc -> match path with
+			| _,_ :: _, _ -> acc
+			| _ -> self#netpath_to_hx path :: acc) (self#get_ctx).nil.il_typedefs []
+
+	method lookup path : net_lib_type =
 		try
 			Hashtbl.find cache path
 		with | Not_found -> try
-			let ctx = get_ctx() in
+			let ctx = self#get_ctx in
 			let ns, n, cl = hxpath_to_net ctx path in
 			let cls = IlMetaTools.convert_class ctx.nil (ns,n,cl) in
 			let cls = normalize_ilcls ctx cls in
@@ -1163,38 +1169,31 @@ let add_net_lib com file std =
 		with | Not_found ->
 			Hashtbl.add cache path None;
 			None
-	in
 
-	let all_files () =
-		Hashtbl.fold (fun path _ acc -> match path with
-			| _,_ :: _, _ -> acc
-			| _ -> netpath_to_hx path :: acc) (get_ctx()).nil.il_typedefs []
-	in
-
-	let build path =
-		let p = { pfile = !real_file ^ " @ " ^ s_type_path path; pmin = 0; pmax = 0; } in
+	method build (path : path) (p : pos) : Ast.package option =
+		let p = { pfile = file_path ^ " @ " ^ s_type_path path; pmin = 0; pmax = 0; } in
 		let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in
 		let cp = ref [] in
 		let rec build path = try
 			if PMap.mem "net_loader_debug" com.defines.Define.values then
 				Printf.printf "looking up %s\n" (s_type_path path);
-			match lookup path with
+			match self#lookup path with
 			| Some({csuper = Some{snorm = LClass( (["System"],[],("Delegate"|"MulticastDelegate")),_)}} as cls)
 				when List.mem SSealed cls.cflags.tdf_semantics ->
-				let ctx = get_ctx() in
+				let ctx = self#get_ctx in
 				let hxcls = convert_ilclass ctx p ~delegate:true cls in
 				let delegate = convert_delegate ctx p cls in
 				cp := (hxcls,p) :: (delegate,p) :: !cp;
 				List.iter (fun ilpath ->
-					let path = netpath_to_hx ilpath in
+					let path = netpath_to_hx std ilpath in
 					build path
 				) cls.cnested
 			| Some cls ->
-				let ctx = get_ctx() in
+				let ctx = self#get_ctx in
 				let hxcls = convert_ilclass ctx p cls in
 				cp := (hxcls,p) :: !cp;
 				List.iter (fun ilpath ->
-					let path = netpath_to_hx ilpath in
+					let path = netpath_to_hx std ilpath in
 					build path
 				) cls.cnested
 			| _ -> ()
@@ -1204,14 +1203,26 @@ let add_net_lib com file std =
 		build path;
 		match !cp with
 			| [] -> None
-			| cp -> Some (!real_file, (pack,cp))
-	in
-	let build path p =
-		build path
-	in
-	com.load_extern_type <- com.load_extern_type @ [build];
-	com.net_libs <- (file, std, all_files, lookup) :: com.net_libs
+			| cp -> Some (pack,cp)
 
+	method get_data = ()
+
+	initializer
+		if std then self#add_flag FlagIsStd
+end
+
+let add_net_lib com file std extern =
+	let real_file = if Sys.file_exists file then
+		file
+	else try Common.find_file com file with
+		| Not_found -> try Common.find_file com (file ^ ".dll") with
+		| Not_found ->
+			failwith (".NET lib " ^ file ^ " not found")
+	in
+	let net_lib = new net_library com file real_file std in
+	if extern then net_lib#add_flag FlagIsExtern;
+	com.native_libs.net_libs <- (net_lib :> (net_lib_type,unit) native_library) :: com.native_libs.net_libs;
+	CompilationServer.handle_native_lib com net_lib
 
 let before_generate com =
 	(* netcore version *)
@@ -1283,13 +1294,10 @@ let before_generate com =
 				let f = Unix.readdir f in
 				let finsens = String.lowercase f in
 				if String.ends_with finsens ".dll" then
-					add_net_lib com (path ^ "/" ^ f) true;
+					add_net_lib com (path ^ "/" ^ f) true false ();
 				loop()
 			with | End_of_file ->
 				Unix.closedir f
 		in
 		loop()
-	) !matched;
-
-	(* now force all libraries to initialize *)
-	List.iter (function (_,_,_,lookup) -> ignore (lookup ([],""))) com.net_libs
+	) !matched

+ 8 - 8
src/codegen/gencommon/gencommon.ml

@@ -947,19 +947,19 @@ let dump_descriptor gen name path_s module_s =
 				file
 	in
 	if Common.platform gen.gcon Java then
-		List.iter (fun (s,std,_,_,_) ->
-			if not std then begin
-				SourceWriter.write w (path s ".jar");
+		List.iter (fun java_lib ->
+			if not (java_lib#has_flag NativeLibraries.FlagIsStd) && not (java_lib#has_flag NativeLibraries.FlagIsExtern) then begin
+				SourceWriter.write w (path java_lib#get_file_path ".jar");
 				SourceWriter.newline w;
 			end
-		) gen.gcon.java_libs
+		) gen.gcon.native_libs.java_libs
 	else if Common.platform gen.gcon Cs then
-		List.iter (fun (s,std,_,_) ->
-			if not std then begin
-				SourceWriter.write w (path s ".dll");
+		List.iter (fun net_lib ->
+			if not (net_lib#has_flag NativeLibraries.FlagIsStd) && not (net_lib#has_flag NativeLibraries.FlagIsExtern) then begin
+				SourceWriter.write w (path net_lib#get_name ".dll");
 				SourceWriter.newline w;
 			end
-		) gen.gcon.net_libs;
+		) gen.gcon.native_libs.net_libs;
 	SourceWriter.write w "end libs";
 	SourceWriter.newline w;
 	let args = gen.gcon.c_args in

+ 299 - 238
src/codegen/java.ml

@@ -18,6 +18,7 @@
 *)
 open Unix
 open ExtString
+open NativeLibraries
 open Common
 open Globals
 open Ast
@@ -31,6 +32,7 @@ type java_lib_ctx = {
 	jcom : Common.context;
 	(* current tparams context *)
 	mutable jtparams : jtypes list;
+	is_std : bool;
 }
 
 exception ConversionError of string * pos
@@ -73,11 +75,11 @@ let real_java_path ctx (pack,name) =
 
 let lookup_jclass com path =
 	let path = jpath_to_hx path in
-	List.fold_right (fun (_,_,_,_,get_raw_class) acc ->
+	List.fold_right (fun java_lib acc ->
 		match acc with
-		| None -> get_raw_class path
+		| None -> java_lib#lookup path
 		| Some p -> Some p
-	) com.java_libs None
+	) com.native_libs.java_libs None
 
 let mk_type_path ctx path params =
 	let name, sub = try
@@ -217,6 +219,12 @@ let del_override field =
 let get_canonical ctx p pack name =
 	(Meta.JavaCanonical, [EConst (String (String.concat "." pack)), p; EConst (String name), p], p)
 
+let show_in_completion ctx jc =
+	if not ctx.is_std then true
+	else match fst jc.cpath with
+		| ("java" | "javax" | "org") :: _ -> true
+		| _ -> false
+
 let convert_java_enum ctx p pe =
 	let meta = ref (get_canonical ctx p (fst pe.cpath) (snd pe.cpath) :: [Meta.Native, [EConst (String (real_java_path ctx pe.cpath) ), p], p ]) in
 	let data = ref [] in
@@ -228,6 +236,8 @@ let convert_java_enum ctx p pe =
 		| _ -> ()
 	) pe.cfields;
 
+	if not (show_in_completion ctx pe) then meta := (Meta.NoCompletion,[],null_pos) :: !meta;
+
 	EEnum {
 		d_name = jname_to_hx (snd pe.cpath),null_pos;
 		d_doc = None;
@@ -466,6 +476,8 @@ let convert_java_enum ctx p pe =
 				) f.jf_throws
 			) jc.cmethods) in
 
+			if not (show_in_completion ctx jc) then meta := (Meta.NoCompletion,[],null_pos) :: !meta;
+
 			(EClass {
 				d_name = jname_to_hx (snd jc.cpath),null_pos;
 				d_doc = None;
@@ -475,10 +487,11 @@ let convert_java_enum ctx p pe =
 				d_data = !fields;
 			}) :: imports
 
-	let create_ctx com =
+	let create_ctx com is_std =
 		{
 			jcom = com;
 			jtparams = [];
+			is_std = is_std;
 		}
 
 	let rec has_type_param = function
@@ -593,7 +606,7 @@ let jclass_with_params com cls params = try
 			cinterfaces = List.map (japply_params jparams) cls.cinterfaces;
 		}
 	with Invalid_argument _ ->
-		if com.verbose then prerr_endline ("Differing parameters for class: " ^ s_type_path cls.cpath);
+		if com.verbose then print_endline ("Differing parameters for class: " ^ s_type_path cls.cpath);
 		cls
 
 let is_object = function | TObject( (["java";"lang"], "Object"), [] ) -> true | _ -> false
@@ -647,8 +660,8 @@ let compare_type com s1 s2 =
 				let implements = List.map (japply_params jparams) c.cinterfaces in
 				loop ~first_error:first_error super s2 || List.exists (fun super -> loop ~first_error:first_error super s2) implements
 			with | Not_found ->
-				prerr_endline ("-java-lib: The type " ^ (s_sig s1) ^ " is referred but was not found. Compilation may not occur correctly.");
-				prerr_endline "Did you forget to include a needed lib?";
+				print_endline ("-java-lib: The type " ^ (s_sig s1) ^ " is referred but was not found. Compilation may not occur correctly.");
+				print_endline "Did you forget to include a needed lib?";
 				if first_error then
 					not (loop ~first_error:false s2 s1)
 				else
@@ -681,13 +694,13 @@ let select_best com flist =
 				| -1 ->
 					loop cur_best flist
 				| -2 -> (* error - no type is compatible *)
-					if com.verbose then prerr_endline (f.jf_name ^ ": The types " ^ (s_sig r) ^ " and " ^ (s_sig r2) ^ " are incompatible");
+					if com.verbose then print_endline (f.jf_name ^ ": The types " ^ (s_sig r) ^ " and " ^ (s_sig r2) ^ " are incompatible");
 					(* bet that the current best has "beaten" other types *)
 					loop cur_best flist
 				| _ -> assert false
 			with | Exit -> (* incompatible type parameters *)
 				(* error mode *)
-				if com.verbose then prerr_endline (f.jf_name ^ ": Incompatible argument return signatures: " ^ (s_sig r) ^ " and " ^ (s_sig r2));
+				if com.verbose then print_endline (f.jf_name ^ ": Incompatible argument return signatures: " ^ (s_sig r) ^ " and " ^ (s_sig r2));
 				None)
 			| TMethod _, _ -> (* select the method *)
 				loop f flist
@@ -778,7 +791,7 @@ let normalize_jclass com cls =
 				List.iter (fun jf ->
 					if not(List.mem JStatic jf.jf_flags) && not (List.exists (fun jf2 -> jf.jf_name = jf2.jf_name && not (List.mem JStatic jf2.jf_flags) && jf.jf_signature = jf2.jf_signature) all_methods) then begin
 						let jf = if abstract && force_check then del_override jf else jf in
-						let jf = { jf with jf_flags = JPublic :: jf.jf_flags } in (* interfaces implementations are always public *)
+						let jf = if not (List.mem JPublic jf.jf_flags) then { jf with jf_flags = JPublic :: jf.jf_flags } else jf in (* interfaces implementations are always public *)
 
 						added_interface_fields := jf :: !added_interface_fields;
 					end
@@ -890,101 +903,15 @@ let get_classes_zip zip =
 	) (Zip.entries zip);
 	!ret
 
-let add_java_lib com file std =
-	let file = if Sys.file_exists file then
-		file
-	else try Common.find_file com file with
-		| Not_found -> try Common.find_file com (file ^ ".jar") with
-		| Not_found ->
-			failwith ("Java lib " ^ file ^ " not found")
-	in
-	let hxpack_to_jpack = Hashtbl.create 16 in
-	let get_raw_class, close, list_all_files =
-		(* check if it is a directory or jar file *)
-		match (Unix.stat file).st_kind with
-		| S_DIR -> (* open classes directly from directory *)
-			let all = ref [] in
-			let rec iter_files pack dir path = try
-				let file = Unix.readdir dir in
-				let filepath = path ^ "/" ^ file in
-				(if String.ends_with file ".class" then
-					let name = String.sub file 0 (String.length file - 6) in
-					let path = jpath_to_hx (pack,name) in
-					if not (String.exists file "$") then all := path :: !all;
-					Hashtbl.add hxpack_to_jpack path (pack,name)
-				else if (Unix.stat filepath).st_kind = S_DIR && file <> "." && file <> ".." then
-					let pack = pack @ [file] in
-					iter_files (pack) (Unix.opendir filepath) filepath);
-				iter_files pack dir path
-			with | End_of_file | Unix.Unix_error _ ->
-				Unix.closedir dir
-			in
-			iter_files [] (Unix.opendir file) file;
-			let all = !all in
-
-			(fun (pack, name) ->
-				let real_path = file ^ "/" ^ (String.concat "/" pack) ^ "/" ^ (name ^ ".class") in
-				try
-					let data = Std.input_file ~bin:true real_path in
-					Some(JReader.parse_class (IO.input_string data), real_path, real_path)
-				with
-					| _ -> None), (fun () -> ()), (fun () -> all)
-		| _ -> (* open zip file *)
-			let closed = ref false in
-			let zip = ref (Zip.open_in file) in
-			let check_open () =
-				if !closed then begin
-					prerr_endline ("JAR file " ^ file ^ " already closed"); (* if this happens, find when *)
-					zip := Zip.open_in file;
-					closed := false
-				end
-			in
-			List.iter (function
-				| { Zip.is_directory = false; Zip.filename = filename } when String.ends_with filename ".class" ->
-					let pack = String.nsplit filename "/" in
-					(match List.rev pack with
-						| [] -> ()
-						| name :: pack ->
-							let name = String.sub name 0 (String.length name - 6) in
-							let pack = List.rev pack in
-							Hashtbl.add hxpack_to_jpack (jpath_to_hx (pack,name)) (pack,name))
-				| _ -> ()
-			) (Zip.entries !zip);
-			(fun (pack, name) ->
-				check_open();
-				try
-					let location = (String.concat "/" (pack @ [name]) ^ ".class") in
-					let entry = Zip.find_entry !zip location in
-					let data = Zip.read_entry !zip entry in
-					Some(JReader.parse_class (IO.input_string data), file, file ^ "@" ^ location)
-				with
-					| Not_found ->
-						None),
-			(fun () -> if not !closed then begin closed := true; Zip.close_in !zip end),
-			(fun () -> check_open(); get_classes_zip !zip)
-	in
-	let cached_types = Hashtbl.create 12 in
-	let get_raw_class path =
-		try
-			Hashtbl.find cached_types path
-		with | Not_found -> try
-			let pack, name = Hashtbl.find hxpack_to_jpack path in
-			let try_file (pack,name) =
-				match get_raw_class (pack,name) with
-				| None ->
-						Hashtbl.add cached_types path None;
-						None
-				| Some (i, p1, p2) ->
-						Hashtbl.add cached_types path (Some(i,p1,p2)); (* type loop normalization *)
-						let ret = Some (normalize_jclass com i, p1, p2) in
-						Hashtbl.replace cached_types path ret;
-						ret
-			in
-			try_file (pack,name)
-		with Not_found ->
-			None
-	in
-	let replace_canonical_name p pack name_original name_replace decl =
+class virtual java_library com name file_path = object(self)
+	inherit [java_lib_type,unit] native_library name file_path as super
+
+	val hxpack_to_jpack = Hashtbl.create 16
+
+	method convert_path (path : path) : path =
+		Hashtbl.find hxpack_to_jpack path
+
+	method private replace_canonical_name p pack name_original name_replace decl =
 		let mk_meta name = (Meta.JavaCanonical, [EConst (String (String.concat "." pack)), p; EConst(String name), p], p) in
 		let add_meta name metas =
 			if Meta.has Meta.JavaCanonical metas then
@@ -1006,145 +933,279 @@ let add_java_lib com file std =
 			| EAbstract a ->
 				EAbstract { a with d_meta = add_meta (fst a.d_name) a.d_meta }
 			| d -> d
-	in
-	let rec build ctx path p types =
+
+	method build path (p : pos) : Ast.package option =
+		let rec build ctx path p types =
+			try
+				if List.mem path !types then
+					None
+				else begin
+					let first = match !types with
+						| [ ["java";"lang"], "String" ] | [] -> true
+						| p :: _ ->
+							false
+					in
+					types := path :: !types;
+					match self#lookup path, path with
+					| None, ([], c) -> build ctx (["haxe";"root"], c) p types
+					| None, _ -> None
+					| Some (cls, real_path, pos_path), _ ->
+							let is_disallowed_inner = first && String.exists (snd cls.cpath) "$" in
+							let is_disallowed_inner = if is_disallowed_inner then begin
+									let outer, inner = String.split (snd cls.cpath) "$" in
+									match self#lookup (fst path, outer) with
+										| None -> false
+										| _ -> true
+								end else
+									false
+							in
+							if is_disallowed_inner then
+								None
+							else begin
+								if ctx.jcom.verbose then print_endline ("Parsed Java class " ^ (s_type_path cls.cpath));
+								let old_types = ctx.jtparams in
+								ctx.jtparams <- cls.ctypes :: ctx.jtparams;
+
+								let pos = { pfile = pos_path; pmin = 0; pmax = 0; } in
+
+								let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in
+
+								let ppath = self#convert_path path in
+								let inner = List.fold_left (fun acc (path,out,_,_) ->
+									let path = jpath_to_hx path in
+									(if out <> Some ppath then
+										acc
+									else match build ctx path p types with
+										| Some(_, classes) ->
+											let base = snd ppath ^ "$" in
+											(List.map (fun (def,p) ->
+												self#replace_canonical_name p (fst ppath) base (snd ppath ^ ".") def, p) classes) @ acc
+										| _ -> acc);
+								) [] cls.cinner_types in
+
+								(* add _Statics class *)
+								let inner = try
+									if not (List.mem JInterface cls.cflags) then raise Not_found;
+									let smethods = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cmethods in
+									let sfields = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cfields in
+									if not (smethods <> [] || sfields <> []) then raise Not_found;
+									let obj = TObject( (["java";"lang"],"Object"), []) in
+									let ncls = convert_java_class ctx pos { cls with cmethods = smethods; cfields = sfields; cflags = []; csuper = obj; cinterfaces = []; cinner_types = []; ctypes = [] } in
+									match ncls with
+									| EClass c :: imports ->
+										(EClass { c with d_name = (fst c.d_name ^ "_Statics"),snd c.d_name }, pos) :: inner @ List.map (fun i -> i,pos) imports
+									| _ -> assert false
+								with | Not_found ->
+									inner
+								in
+								let inner_alias = ref SS.empty in
+								List.iter (fun x ->
+									match fst x with
+									| EClass c ->
+										inner_alias := SS.add (fst c.d_name) !inner_alias;
+									| _ -> ()
+								) inner;
+								let alias_list = ref [] in
+								List.iter (fun x ->
+									match x with
+									| (EClass c, pos) -> begin
+										let parts = String.nsplit (fst c.d_name) "_24" in
+										match parts with
+											| _ :: _ ->
+												let alias_name = String.concat "_" parts in
+												if (not (SS.mem alias_name !inner_alias)) && (not (String.exists (snd path) "_24")) then begin
+													let alias_def = ETypedef {
+														d_name = alias_name,null_pos;
+														d_doc = None;
+														d_params = c.d_params;
+														d_meta = [];
+														d_flags = [];
+														d_data = CTPath {
+															tpackage = pack;
+															tname = snd path;
+															tparams = List.map (fun tp ->
+																TPType (CTPath {
+																	tpackage = [];
+																	tname = fst tp.tp_name;
+																	tparams = [];
+																	tsub = None;
+																},null_pos)
+															) c.d_params;
+															tsub = Some(fst c.d_name);
+														},null_pos;
+													} in
+													inner_alias := SS.add alias_name !inner_alias;
+													alias_list := (alias_def, pos) :: !alias_list;
+												end
+											| _ -> ()
+									end
+									| _ -> ()
+								) inner;
+								let inner = List.concat [!alias_list ; inner] in
+								let classes = List.map (fun t -> t,pos) (convert_java_class ctx pos cls) in
+								let imports, defs = List.partition (function | (EImport(_),_) -> true | _ -> false) (classes @ inner) in
+								let ret = Some (pack, imports @ defs) in
+								ctx.jtparams <- old_types;
+								ret
+							end
+				end
+			with
+			| JReader.Error_message msg ->
+				print_endline ("Class reader failed: " ^ msg);
+				None
+			| e ->
+				if ctx.jcom.verbose then begin
+					(* print_endline (Printexc.get_backtrace ()); requires ocaml 3.11 *)
+					print_endline (Printexc.to_string e)
+				end;
+				None
+		in
+		build (create_ctx com (self#has_flag FlagIsStd)) path p (ref [["java";"lang"], "String"])
+
+	method get_data = ()
+end
+
+class java_library_jar com name file_path = object(self)
+	inherit java_library com name file_path
+
+	val zip = lazy (Zip.open_in file_path)
+	val mutable cached_files = None
+	val cached_types = Hashtbl.create 12
+	val mutable closed = false
+
+	method load =
+		List.iter (function
+			| { Zip.is_directory = false; Zip.filename = filename } when String.ends_with filename ".class" ->
+				let pack = String.nsplit filename "/" in
+				(match List.rev pack with
+					| [] -> ()
+					| name :: pack ->
+						let name = String.sub name 0 (String.length name - 6) in
+						let pack = List.rev pack in
+						Hashtbl.add hxpack_to_jpack (jpath_to_hx (pack,name)) (pack,name))
+			| _ -> ()
+		) (Zip.entries (Lazy.force zip))
+
+	method private lookup' ((pack,name) : path) : java_lib_type =
 		try
-			if List.mem path !types then
+			let zip = Lazy.force zip in
+			let location = (String.concat "/" (pack @ [name]) ^ ".class") in
+			let entry = Zip.find_entry zip location in
+			let data = Zip.read_entry zip entry in
+			Some(JReader.parse_class (IO.input_string data), file_path, file_path ^ "@" ^ location)
+		with
+			| Not_found ->
 				None
-			else begin
-				let first = match !types with
-					| [ ["java";"lang"], "String" ] | [] -> true
-					| p :: _ ->
-						false
-				in
-				types := path :: !types;
-				match get_raw_class path, path with
-				| None, ([], c) -> build ctx (["haxe";"root"], c) p types
-				| None, _ -> None
-				| Some (cls, real_path, pos_path), _ ->
-						let is_disallowed_inner = first && String.exists (snd cls.cpath) "$" in
-						let is_disallowed_inner = if is_disallowed_inner then begin
-								let outer, inner = String.split (snd cls.cpath) "$" in
-								match get_raw_class (fst path, outer) with
-									| None -> false
-									| _ -> true
-							end else
-								false
-						in
-						if is_disallowed_inner then
-							None
-						else begin
-							if com.verbose then print_endline ("Parsed Java class " ^ (s_type_path cls.cpath));
-							let old_types = ctx.jtparams in
-							ctx.jtparams <- cls.ctypes :: ctx.jtparams;
-
-							let pos = { pfile = pos_path; pmin = 0; pmax = 0; } in
-
-							let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in
-
-							let ppath = Hashtbl.find hxpack_to_jpack path in
-							let inner = List.fold_left (fun acc (path,out,_,_) ->
-								let path = jpath_to_hx path in
-								(if out <> Some ppath then
-									acc
-								else match build ctx path p types with
-									| Some(_,(_, classes)) ->
-										let base = snd ppath ^ "$" in
-										(List.map (fun (def,p) ->
-											replace_canonical_name p (fst ppath) base (snd ppath ^ ".") def, p) classes) @ acc
-									| _ -> acc);
-							) [] cls.cinner_types in
-
-							(* add _Statics class *)
-							let inner = try
-								if not (List.mem JInterface cls.cflags) then raise Not_found;
-								let smethods = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cmethods in
-								let sfields = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cfields in
-								if not (smethods <> [] || sfields <> []) then raise Not_found;
-								let obj = TObject( (["java";"lang"],"Object"), []) in
-								let ncls = convert_java_class ctx pos { cls with cmethods = smethods; cfields = sfields; cflags = []; csuper = obj; cinterfaces = []; cinner_types = []; ctypes = [] } in
-								match ncls with
-								| EClass c :: imports ->
-									(EClass { c with d_name = (fst c.d_name ^ "_Statics"),snd c.d_name }, pos) :: inner @ List.map (fun i -> i,pos) imports
-								| _ -> assert false
-							with | Not_found ->
-								inner
-							in
-							let inner_alias = ref SS.empty in
-							List.iter (fun x ->
-								match fst x with
-								| EClass c ->
-									inner_alias := SS.add (fst c.d_name) !inner_alias;
-								| _ -> ()
-							) inner;
-							let alias_list = ref [] in
-							List.iter (fun x ->
-								match x with
-								| (EClass c, pos) -> begin
-									let parts = String.nsplit (fst c.d_name) "_24" in
-									match parts with
-										| _ :: _ ->
-											let alias_name = String.concat "_" parts in
-											if (not (SS.mem alias_name !inner_alias)) && (not (String.exists (snd path) "_24")) then begin
-												let alias_def = ETypedef {
-													d_name = alias_name,null_pos;
-													d_doc = None;
-													d_params = c.d_params;
-													d_meta = [];
-													d_flags = [];
-													d_data = CTPath {
-														tpackage = pack;
-														tname = snd path;
-														tparams = List.map (fun tp ->
-															TPType (CTPath {
-																tpackage = [];
-																tname = fst tp.tp_name;
-																tparams = [];
-																tsub = None;
-															},null_pos)
-														) c.d_params;
-														tsub = Some(fst c.d_name);
-													},null_pos;
-												} in
-												inner_alias := SS.add alias_name !inner_alias;
-												alias_list := (alias_def, pos) :: !alias_list;
-											end
-										| _ -> ()
-								end
-								| _ -> ()
-							) inner;
-							let inner = List.concat [!alias_list ; inner] in
-							let classes = List.map (fun t -> t,pos) (convert_java_class ctx pos cls) in
-							let imports, defs = List.partition (function | (EImport(_),_) -> true | _ -> false) (classes @ inner) in
-							let ret = Some ( real_path, (pack, imports @ defs) ) in
-							ctx.jtparams <- old_types;
-							ret
+
+	method lookup (path : path) : java_lib_type =
+		try
+			Hashtbl.find cached_types path
+		with | Not_found -> try
+			let pack, name = self#convert_path path in
+			let try_file (pack,name) =
+				match self#lookup' (pack,name) with
+				| None ->
+						Hashtbl.add cached_types path None;
+						None
+				| Some (i, p1, p2) ->
+						Hashtbl.add cached_types path (Some(i,p1,p2)); (* type loop normalization *)
+						let ret = Some (normalize_jclass com i, p1, p2) in
+						Hashtbl.replace cached_types path ret;
+						ret
+			in
+			try_file (pack,name)
+		with Not_found ->
+			None
+
+	method close =
+		if not closed then begin
+			closed <- true;
+			Zip.close_in (Lazy.force zip)
+		end
+
+	method private list_modules' : path list =
+		let ret = ref [] in
+		List.iter (function
+			| { Zip.is_directory = false; Zip.filename = f } when (String.sub (String.uncapitalize f) (String.length f - 6) 6) = ".class" && not (String.exists f "$") ->
+					(match List.rev (String.nsplit f "/") with
+					| clsname :: pack ->
+						if not (String.contains clsname '$') then begin
+							let path = jpath_to_hx (List.rev pack, String.sub clsname 0 (String.length clsname - 6)) in
+							ret := path :: !ret
 						end
-			end
+					| _ ->
+							ret := ([], jname_to_hx f) :: !ret)
+			| _ -> ()
+		) (Zip.entries (Lazy.force zip));
+		!ret
+
+	method list_modules : path list = match cached_files with
+		| None ->
+			let ret = self#list_modules' in
+			cached_files <- Some ret;
+			ret
+		| Some r ->
+			r
+end
+
+class java_library_dir com name file_path = object(self)
+	inherit java_library com name file_path
+
+	val mutable files = []
+
+	method load =
+		let all = ref [] in
+		let rec iter_files pack dir path = try
+			let file = Unix.readdir dir in
+			let filepath = path ^ "/" ^ file in
+			(if String.ends_with file ".class" then
+				let name = String.sub file 0 (String.length file - 6) in
+				let path = jpath_to_hx (pack,name) in
+				if not (String.exists file "$") then all := path :: !all;
+				Hashtbl.add hxpack_to_jpack path (pack,name)
+			else if (Unix.stat filepath).st_kind = S_DIR && file <> "." && file <> ".." then
+				let pack = pack @ [file] in
+				iter_files (pack) (Unix.opendir filepath) filepath);
+			iter_files pack dir path
+		with | End_of_file | Unix.Unix_error _ ->
+			Unix.closedir dir
+		in
+		iter_files [] (Unix.opendir file_path) file_path;
+		files <- !all
+
+	method close =
+		()
+
+	method list_modules =
+		files
+
+	method lookup (pack,name) : java_lib_type =
+		let real_path = file_path ^ "/" ^ (String.concat "/" pack) ^ "/" ^ (name ^ ".class") in
+		try
+			let data = Std.input_file ~bin:true real_path in
+			Some(JReader.parse_class (IO.input_string data), real_path, real_path)
 		with
-		| JReader.Error_message msg ->
-			prerr_endline ("Class reader failed: " ^ msg);
-			None
-		| e ->
-			if com.verbose then begin
-				(* prerr_endline (Printexc.get_backtrace ()); requires ocaml 3.11 *)
-				prerr_endline (Printexc.to_string e)
-			end;
-			None
+			| _ -> None
+end
+
+let add_java_lib com name std extern =
+	let file = if Sys.file_exists name then
+		name
+	else try Common.find_file com name with
+		| Not_found -> try Common.find_file com (name ^ ".jar") with
+		| Not_found ->
+			failwith ("Java lib " ^ name ^ " not found")
 	in
-	let build path p = build (create_ctx com) path p (ref [["java";"lang"], "String"]) in
-	let cached_files = ref None in
-	let list_all_files () = match !cached_files with
-		| None ->
-				let ret = list_all_files () in
-				cached_files := Some ret;
-				ret
-		| Some r -> r
+	let java_lib = match (Unix.stat file).st_kind with
+		| S_DIR ->
+			(new java_library_dir com name file :> java_library)
+		| _ ->
+			(new java_library_jar com name file :> java_library)
 	in
-
-	(* TODO: add_dependency m mdep *)
-	com.load_extern_type <- com.load_extern_type @ [build];
-	com.java_libs <- (file, std, close, list_all_files, get_raw_class) :: com.java_libs
+	if std then java_lib#add_flag FlagIsStd;
+	if extern then java_lib#add_flag FlagIsExtern;
+	com.native_libs.java_libs <- (java_lib :> (java_lib_type,unit) native_library) :: com.native_libs.java_libs;
+	CompilationServer.handle_native_lib com java_lib
 
 let before_generate con =
 	let java_ver = try

+ 57 - 28
src/codegen/swfLoader.ml

@@ -22,6 +22,7 @@ open As3hl
 open Common
 open Globals
 open Ast
+open NativeLibraries
 
 let lowercase_pack pack =
 	let rec loop acc pack =
@@ -131,10 +132,10 @@ let is_valid_path com pack name =
 	let rec loop = function
 		| [] ->
 			false
-		| load :: l ->
+		| (file,load) :: l ->
 			match load (pack,name) null_pos with
 			| None -> loop l
-			| Some (file,(_,a)) -> true
+			| Some (_,a) -> true
 	in
 	let file = Printf.sprintf "%s/%s.hx" (String.concat "/" pack) name in
 	loop com.load_extern_type || (try ignore(Common.find_file com file); true with Not_found -> false)
@@ -541,7 +542,6 @@ let remove_debug_infos as3 =
 let parse_swf com file =
 	let t = Timer.timer ["read";"swf"] in
 	let is_swc = file_extension file = "swc" || file_extension file = "ane" in
-	let file = (try Common.find_file com file with Not_found -> failwith ((if is_swc then "SWC" else "SWF") ^ " Library not found : " ^ file)) in
 	let ch = if is_swc then begin
 		let zip = Zip.open_in file in
 		try
@@ -572,39 +572,68 @@ let parse_swf com file =
 	t();
 	(h,tags)
 
-let add_swf_lib com file extern =
-	let swf_data = ref None in
-	let swf_classes = ref None in
-	let getSWF = (fun() ->
-		match !swf_data with
+class swf_library com name file_path = object(self)
+	inherit [swf_lib_type,Swf.swf] native_library name file_path
+
+	val mutable swf_data = None
+	val mutable swf_classes = None
+	val haxe_classes = Hashtbl.create 0
+
+	method load =
+		ignore(self#get_swf)
+
+	method get_swf = match swf_data with
 		| None ->
-			let d = parse_swf com file in
-			swf_data := Some d;
+			let d = parse_swf com file_path in
+			swf_data <- Some d;
 			d
-		| Some d -> d
-	) in
-	let extract = (fun() ->
-		match !swf_classes with
+		| Some d ->
+			d
+
+	method extract = match swf_classes with
 		| None ->
-			let d = extract_data (getSWF()) in
-			swf_classes := Some d;
+			let d = extract_data self#get_swf in
+			swf_classes <- Some d;
 			d
-		| Some d -> d
-	) in
-	let build cl p =
-		match (try Some (Hashtbl.find (extract()) cl) with Not_found -> None) with
-		| None -> None
-		| Some c -> Some (file, build_class com c file)
-	in
-	com.load_extern_type <- com.load_extern_type @ [build];
-	if not extern then com.swf_libs <- (file,getSWF,extract) :: com.swf_libs
+		| Some d ->
+			d
+
+	method lookup path =
+		try Some (Hashtbl.find (self#extract) path)
+		with Not_found -> None
+
+	method list_modules =
+		Hashtbl.fold (fun path _ acc -> path :: acc) (self#extract) []
+
+	method close =
+		()
+
+	method build (path : path) (p : pos) : Ast.package option =
+		try
+			Some (Hashtbl.find haxe_classes path)
+		with Not_found -> try
+			let c = Hashtbl.find (self#extract) path in
+			let c = build_class com c file_path in
+			Hashtbl.add haxe_classes path c;
+			Some c
+		with Not_found ->
+			None
+
+	method get_data = self#get_swf
+end
+
+let add_swf_lib com file extern =
+	let real_file = (try Common.find_file com file with Not_found -> failwith (" Library not found : " ^ file)) in
+	let swf_lib = new swf_library com file real_file in
+	if not extern then com.native_libs.swf_libs <- (swf_lib :> (swf_lib_type,Swf.swf) native_library) :: com.native_libs.swf_libs;
+	CompilationServer.handle_native_lib com swf_lib
 
-let remove_classes toremove lib hcl =
-	let lib = lib() in
+let remove_classes toremove lib l =
 	match !toremove with
 	| [] -> lib
 	| _ ->
-		let hcl = hcl() in
+		let hcl = Hashtbl.create 0 in
+		List.iter (fun path -> Hashtbl.add hcl path ()) l;
 		match List.filter (fun c -> Hashtbl.mem hcl c) (!toremove) with
 		| [] -> lib
 		| classes ->

+ 9 - 29
src/compiler/displayOutput.ml

@@ -328,6 +328,7 @@ module Memory = struct
 				"haxelibCache",jint (mem_size cs.cache.c_haxelib);
 				"parserCache",jint (mem_size cs.cache.c_files);
 				"moduleCache",jint (mem_size cs.cache.c_modules);
+				"nativeLibCache",jint (mem_size cs.cache.c_native_libs);
 			]
 		]
 
@@ -444,8 +445,8 @@ module TypePathHandler = struct
 				end;
 			) r;
 		) com.class_path;
-		List.iter (fun (_,_,extract) ->
-			Hashtbl.iter (fun (path,name) _ ->
+		let process_lib lib =
+			List.iter (fun (path,name) ->
 				if path = p then classes := name :: !classes else
 				let rec loop p1 p2 =
 					match p1, p2 with
@@ -454,32 +455,11 @@ module TypePathHandler = struct
 					| a :: p1, b :: p2 -> if a = b then loop p1 p2
 				in
 				loop path p
-			) (extract());
-		) com.swf_libs;
-		List.iter (fun (path,std,close,all_files,lookup) ->
-			List.iter (fun (path, name) ->
-				if path = p then classes := name :: !classes else
-				let rec loop p1 p2 =
-					match p1, p2 with
-					| [], _ -> ()
-					| x :: _, [] -> packages := x :: !packages
-					| a :: p1, b :: p2 -> if a = b then loop p1 p2
-				in
-				loop path p
-			) (all_files())
-		) com.java_libs;
-		List.iter (fun (path,std,all_files,lookup) ->
-			List.iter (fun (path, name) ->
-				if path = p then classes := name :: !classes else
-				let rec loop p1 p2 =
-					match p1, p2 with
-					| [], _ -> ()
-					| x :: _, [] -> packages := x :: !packages
-					| a :: p1, b :: p2 -> if a = b then loop p1 p2
-				in
-			loop path p
-			) (all_files())
-		) com.net_libs;
+			) lib#list_modules;
+		in
+		List.iter process_lib com.native_libs.swf_libs;
+		List.iter process_lib com.native_libs.net_libs;
+		List.iter process_lib com.native_libs.java_libs;
 		unique !packages, unique !classes
 
 	(** raise field completion listing packages and modules in a given package *)
@@ -806,4 +786,4 @@ let handle_syntax_completion com kind p =
 			raise (Completion s)
 		| Some(f,_,jsonrpc) ->
 			let ctx = Genjson.create_context ~jsonrpc:jsonrpc GMFull in
-			f(fields_to_json ctx l kind None)
+			f(fields_to_json ctx l kind None None)

+ 40 - 46
src/compiler/main.ml

@@ -246,7 +246,7 @@ module Initialize = struct
 			| Cs ->
 				let old_flush = ctx.flush in
 				ctx.flush <- (fun () ->
-					com.net_libs <- [];
+					com.native_libs.net_libs <- [];
 					old_flush()
 				);
 				Dotnet.before_generate com;
@@ -254,12 +254,15 @@ module Initialize = struct
 			| Java ->
 				let old_flush = ctx.flush in
 				ctx.flush <- (fun () ->
-					List.iter (fun (_,_,close,_,_) -> close()) com.java_libs;
-					com.java_libs <- [];
+					List.iter (fun java_lib -> java_lib#close) com.native_libs.java_libs;
+					com.native_libs.java_libs <- [];
 					old_flush()
 				);
 				Java.before_generate com;
-				if defined com Define.Jvm then add_std "jvm";
+				if defined com Define.Jvm then begin
+					add_std "jvm";
+					com.package_rules <- PMap.remove "jvm" com.package_rules;
+				end;
 				add_std "java";
 				"java"
 			| Python ->
@@ -361,19 +364,19 @@ let get_std_class_paths () =
 			let lib_path = Filename.concat prefix_path "lib" in
 			let share_path = Filename.concat prefix_path "share" in
 			[
+				"";
 				Path.add_trailing_slash (Filename.concat lib_path "haxe/std");
 				Path.add_trailing_slash (Filename.concat lib_path "haxe/extraLibs");
 				Path.add_trailing_slash (Filename.concat share_path "haxe/std");
 				Path.add_trailing_slash (Filename.concat share_path "haxe/extraLibs");
 				Path.add_trailing_slash (Filename.concat base_path "std");
-				Path.add_trailing_slash (Filename.concat base_path "extraLibs");
-				""
+				Path.add_trailing_slash (Filename.concat base_path "extraLibs")
 			]
 		else
 			[
+				"";
 				Path.add_trailing_slash (Filename.concat base_path "std");
-				Path.add_trailing_slash (Filename.concat base_path "extraLibs");
-				""
+				Path.add_trailing_slash (Filename.concat base_path "extraLibs")
 			]
 
 let rec process_params create pl =
@@ -482,6 +485,8 @@ try
 	let pre_compilation = ref [] in
 	let interp = ref false in
 	let swf_version = ref false in
+	let native_libs = ref [] in
+	let add_native_lib file extern = native_libs := (file,extern) :: !native_libs in
 	Common.define_value com Define.HaxeVer (Printf.sprintf "%.3f" (float_of_int Globals.version /. 1000.));
 	Common.raw_define com "haxe3";
 	Common.raw_define com "haxe4";
@@ -515,7 +520,6 @@ try
 		| [] -> ()
 		| args -> (!process_ref) args
 	in
-	let arg_delays = ref [] in
 	(* category, official names, deprecated names, arg spec, usage hint, doc *)
 	let basic_args_spec = [
 		("Target",["--js"],["-js"],Arg.String (Initialize.set_platform com Js),"<file>","compile code to JavaScript file");
@@ -644,29 +648,20 @@ try
 			with
 				_ -> raise (Arg.Bad "Invalid SWF header format, expected width:height:fps[:color]")
 		),"<header>","define SWF header (width:height:fps:color)");
-		(* FIXME: replace with -D define *)
-		("Target-specific",["--swf-lib"],["-swf-lib"],Arg.String (fun file ->
+		("Target-specific",["--flash-strict"],[], define Define.FlashStrict, "","more type strict flash API");
+		("Target-specific",[],["--swf-lib";"-swf-lib"],Arg.String (fun file ->
 			process_libs(); (* linked swf order matters, and lib might reference swf as well *)
-			SwfLoader.add_swf_lib com file false
+			add_native_lib file false;
 		),"<file>","add the SWF library to the compiled SWF");
 		(* FIXME: replace with -D define *)
-		("Target-specific",["--swf-lib-extern"],["-swf-lib-extern"],Arg.String (fun file ->
-			SwfLoader.add_swf_lib com file true
+		("Target-specific",[],["--swf-lib-extern";"-swf-lib-extern"],Arg.String (fun file ->
+			add_native_lib file true;
 		),"<file>","use the SWF library for type checking");
-		("Target-specific",["--flash-strict"],[], define Define.FlashStrict, "","more type strict flash API");
-		("Target-specific",["--java-lib"],["-java-lib"],Arg.String (fun file ->
-			let std = file = "lib/hxjava-std.jar" in
-			arg_delays := (fun () -> Java.add_java_lib com file std) :: !arg_delays;
+		("Target-specific",[],["--java-lib";"-java-lib"],Arg.String (fun file ->
+			add_native_lib file false;
 		),"<file>","add an external JAR or class directory library");
-		("Target-specific",["--net-lib"],["-net-lib"],Arg.String (fun file ->
-			let file, is_std = match ExtString.String.nsplit file "@" with
-				| [file] ->
-					file,false
-				| [file;"std"] ->
-					file,true
-				| _ -> raise Exit
-			in
-			arg_delays := (fun () -> Dotnet.add_net_lib com file is_std) :: !arg_delays;
+		("Target-specific",[],["--net-lib";"-net-lib"],Arg.String (fun file ->
+			add_native_lib file false;
 		),"<file>[@std]","add an external .NET DLL file");
 		("Target-specific",["--net-std"],["-net-std"],Arg.String (fun file ->
 			Dotnet.add_net_std com file
@@ -777,7 +772,6 @@ try
 			in
 			let args = loop [] args in
 			Arg.parse_argv ~current (Array.of_list ("" :: args)) all_args_spec args_callback "";
-			List.iter (fun fn -> fn()) !arg_delays
 		with
 		| Arg.Help _ ->
 			raise (HelpMessage (usage_string all_args usage))
@@ -801,7 +795,6 @@ try
 				end;
 			with Not_found ->
 				raise (Arg.Bad new_msg));
-		arg_delays := [];
 		if com.platform = Globals.Cpp && not (Define.defined com.defines DisableUnicodeStrings) && not (Define.defined com.defines HxcppSmartStings) then begin
 			Define.define com.defines HxcppSmartStings;
 		end;
@@ -809,17 +802,13 @@ try
 			(* TODO: this is something we're gonna remove once we have something nicer for generating flash externs *)
 			force_typing := true;
 			pre_compilation := (fun() ->
-				List.iter (fun (_,_,extract) ->
-					Hashtbl.iter (fun n _ -> classes := n :: !classes) (extract())
-				) com.swf_libs;
-				List.iter (fun (_,std,_,all_files,_) ->
-					if not std then
-						List.iter (fun path -> if path <> (["java";"lang"],"String") then classes := path :: !classes) (all_files())
-				) com.java_libs;
-				List.iter (fun (_,std,all_files,_) ->
-					if not std then
-						List.iter (fun path -> classes := path :: !classes) (all_files())
-				) com.net_libs;
+				let process_lib lib =
+					if not (lib#has_flag NativeLibraries.FlagIsStd) then
+						List.iter (fun path -> if path <> (["java";"lang"],"String") then classes := path :: !classes) lib#list_modules
+				in
+				List.iter process_lib com.native_libs.net_libs;
+				List.iter process_lib com.native_libs.swf_libs;
+				List.iter process_lib com.native_libs.java_libs;
 			) :: !pre_compilation;
 			xml_out := Some "hx"
 		end;
@@ -884,7 +873,12 @@ try
 		Common.log com ("Classpath: " ^ (String.concat ";" com.class_path));
 		Common.log com ("Defines: " ^ (String.concat ";" (PMap.foldi (fun k v acc -> (match v with "1" -> k | _ -> k ^ "=" ^ v) :: acc) com.defines.Define.values [])));
 		let t = Timer.timer ["typing"] in
-		Typecore.type_expr_ref := (fun ctx e with_type -> Typer.type_expr ctx e with_type);
+		Typecore.type_expr_ref := (fun ?(mode=MGet) ctx e with_type -> Typer.type_expr ~mode ctx e with_type);
+		List.iter (fun f -> f ()) (List.rev com.callbacks#get_before_typer_create);
+		(* Native lib pass 1: Register *)
+		let fl = List.map (fun (file,extern) -> NativeLibraryHandler.add_native_lib com file extern) !native_libs in
+		(* Native lib pass 2: Initialize *)
+		List.iter (fun f -> f()) fl;
 		let tctx = Typer.create com in
 		let add_signature desc =
 			Option.may (fun cs -> CompilationServer.maybe_add_context_sign cs com desc) (CompilationServer.get ());
@@ -1055,17 +1049,17 @@ with
 	| DisplayException(DisplayPackage pack) ->
 		DisplayPosition.display_position#reset;
 		raise (DisplayOutput.Completion (String.concat "." pack))
-	| DisplayException(DisplayFields Some(fields,cr,_)) ->
+	| DisplayException(DisplayFields Some r) ->
 		DisplayPosition.display_position#reset;
 		let fields = if !measure_times then begin
 			Timer.close_times();
 			(List.map (fun (name,value) ->
 				CompletionItem.make_ci_timer ("@TIME " ^ name) value
-			) (DisplayOutput.get_timer_fields !start_time)) @ fields
+			) (DisplayOutput.get_timer_fields !start_time)) @ r.fitems
 		end else
-			fields
+			r.fitems
 		in
-		let s = match cr with
+		let s = match r.fkind with
 			| CRToplevel _
 			| CRTypeHint
 			| CRExtends
@@ -1120,7 +1114,7 @@ with
 					| [] -> [],""
 				in
 				let kind = CRField ((CompletionItem.make_ci_module path,pos,None,None)) in
-				f (DisplayException.fields_to_json ctx fields kind None);
+				f (DisplayException.fields_to_json ctx fields kind None None);
 			| _ -> raise (DisplayOutput.Completion (DisplayOutput.print_fields fields))
 			end
 		end

+ 20 - 4
src/compiler/server.ml

@@ -257,6 +257,8 @@ let rec wait_loop process_params verbose accept =
 	let compilation_step = ref 0 in
 	let compilation_mark = ref 0 in
 	let mark_loop = ref 0 in
+	let removed_modules = ref [] in
+	let is_removed_module m = List.exists (fun (_,m') -> m == m') !removed_modules in
 	TypeloadModule.type_module_hook := (fun (ctx:Typecore.typer) mpath p ->
 		let t = Timer.timer ["server";"module cache"] in
 		let com2 = ctx.Typecore.com in
@@ -292,10 +294,10 @@ let rec wait_loop process_params verbose accept =
 						| [] ->
 							if verbose then print_endline ("No library file was found for " ^ s_type_path m.m_path); (* TODO *)
 							raise Not_found (* no extern registration *)
-						| load :: l ->
+						| (file,load) :: l ->
 							match load m.m_path p with
 							| None -> loop l
-							| Some (file,_) ->
+							| Some _ ->
 								if Path.unique_full_path file <> m.m_extra.m_file then begin
 									if verbose then print_endline ("Library file was changed for " ^ s_type_path m.m_path); (* TODO *)
 									raise Not_found;
@@ -373,6 +375,8 @@ let rec wait_loop process_params verbose accept =
 				| MCode, MMacro | MMacro, MCode ->
 					(* this was just a dependency to check : do not add to the context *)
 					PMap.iter (Hashtbl.replace com2.resources) m.m_extra.m_binded_res;
+				| _ when is_removed_module m ->
+					()
 				| _ ->
 					ServerMessage.reusing com2 tabs m;
 					m.m_extra.m_added <- !compilation_step;
@@ -422,11 +426,22 @@ let rec wait_loop process_params verbose accept =
 	while true do
 		let read, write, close = accept() in
 		let was_compilation = ref false in
+		let recache_removed_modules () =
+			List.iter (fun (k,m) ->
+				try
+					ignore(CompilationServer.find_module cs k);
+				with Not_found ->
+					CompilationServer.cache_module cs k m
+			) !removed_modules;
+			removed_modules := [];
+		in
 		let maybe_cache_context com =
 			if com.display.dms_full_typing then begin
 				CompilationServer.cache_context cs com;
 				ServerMessage.cached_modules com "" (List.length com.modules);
-			end;
+				removed_modules := [];
+			end else
+				recache_removed_modules();
 		in
 		let create params =
 			let ctx = create_context params in
@@ -460,7 +475,8 @@ let rec wait_loop process_params verbose accept =
 					let fkey = (file,sign) in
 					(* force parsing again : if the completion point have been changed *)
 					CompilationServer.remove_file cs fkey;
-					CompilationServer.taint_modules cs file;
+					removed_modules := CompilationServer.filter_modules cs file;
+					delays := recache_removed_modules :: !delays;
 				end;
 				try
 					if (Hashtbl.find arguments sign) <> ctx.com.class_path then begin

+ 75 - 22
src/context/common.ml

@@ -21,6 +21,7 @@ open Ast
 open Type
 open Globals
 open Define
+open NativeLibraries
 
 type package_rule =
 	| Forbidden
@@ -107,6 +108,7 @@ type platform_config = {
 }
 
 class compiler_callbacks = object(self)
+	val mutable before_typer_create = [];
 	val mutable after_init_macros = [];
 	val mutable after_typing = [];
 	val mutable before_save = [];
@@ -115,6 +117,9 @@ class compiler_callbacks = object(self)
 	val mutable after_generation = [];
 	val mutable null_safety_report = [];
 
+	method add_before_typer_create (f : unit -> unit) : unit =
+		before_typer_create <- f :: before_typer_create
+
 	method add_after_init_macros (f : unit -> unit) : unit =
 		after_init_macros <- f :: after_init_macros
 
@@ -136,6 +141,7 @@ class compiler_callbacks = object(self)
 	method add_null_safety_report (f : (string*pos) list -> unit) : unit =
 		null_safety_report <- f :: null_safety_report
 
+	method get_before_typer_create = before_typer_create
 	method get_after_init_macros = after_init_macros
 	method get_after_typing = after_typing
 	method get_before_save = before_save
@@ -182,13 +188,14 @@ type context = {
 	mutable warning : string -> pos -> unit;
 	mutable get_messages : unit -> compiler_message list;
 	mutable filter_messages : (compiler_message -> bool) -> unit;
-	mutable load_extern_type : (path -> pos -> (string * Ast.package) option) list; (* allow finding types which are not in sources *)
+	mutable load_extern_type : (string * (path -> pos -> Ast.package option)) list; (* allow finding types which are not in sources *)
 	callbacks : compiler_callbacks;
 	defines : Define.define;
 	mutable print : string -> unit;
 	mutable get_macros : unit -> context option;
 	mutable run_command : string -> int;
 	file_lookup_cache : (string,string option) Hashtbl.t;
+	readdir_cache : (string * string,(string array) option) Hashtbl.t;
 	parser_cache : (string,(type_def * pos) list) Hashtbl.t;
 	module_to_file : (path,string) Hashtbl.t;
 	cached_macros : (path * string,(((string * bool * t) list * t * tclass * Type.tclass_field) * module_def)) Hashtbl.t;
@@ -204,9 +211,7 @@ type context = {
 	mutable resources : (string,string) Hashtbl.t;
 	mutable neko_libs : string list;
 	mutable include_files : (string * string) list;
-	mutable swf_libs : (string * (unit -> Swf.swf) * (unit -> ((string list * string),As3hl.hl_class) Hashtbl.t)) list;
-	mutable java_libs : (string * bool * (unit -> unit) * (unit -> (path list)) * (path -> ((JData.jclass * string * string) option))) list; (* (path,std,close,all_files,lookup) *)
-	mutable net_libs : (string * bool * (unit -> path list) * (path -> IlData.ilclass option)) list; (* (path,std,all_files,lookup) *)
+	mutable native_libs : native_libraries;
 	mutable net_std : string list;
 	net_path_map : (path,string list * string list * string) Hashtbl.t;
 	mutable c_args : string list;
@@ -436,10 +441,8 @@ let create version s_version args =
 		main = None;
 		flash_version = 10.;
 		resources = Hashtbl.create 0;
-		swf_libs = [];
-		java_libs = [];
-		net_libs = [];
 		net_std = [];
+		native_libs = create_native_libs();
 		net_path_map = Hashtbl.create 0;
 		c_args = [];
 		neko_libs = [];
@@ -467,6 +470,7 @@ let create version s_version args =
 			tarray = (fun _ -> assert false);
 		};
 		file_lookup_cache = Hashtbl.create 0;
+		readdir_cache = Hashtbl.create 0;
 		module_to_file = Hashtbl.create 0;
 		stored_typed_exprs = PMap.empty;
 		cached_macros = Hashtbl.create 0;
@@ -485,6 +489,7 @@ let clone com =
 		main_class = None;
 		features = Hashtbl.create 0;
 		file_lookup_cache = Hashtbl.create 0;
+		readdir_cache = Hashtbl.create 0;
 		parser_cache = Hashtbl.create 0;
 		module_to_file = Hashtbl.create 0;
 		callbacks = new compiler_callbacks;
@@ -495,7 +500,8 @@ let clone com =
 		defines = {
 			values = com.defines.values;
 			defines_signature = com.defines.defines_signature;
-		}
+		};
+		native_libs = create_native_libs();
 	}
 
 let file_time file = Extc.filetime file
@@ -536,7 +542,7 @@ let init_platform com pf =
 	com.platform <- pf;
 	let name = platform_name pf in
 	let forbid acc p = if p = name || PMap.mem p acc then acc else PMap.add p Forbidden acc in
-	com.package_rules <- List.fold_left forbid com.package_rules (List.map platform_name platforms);
+	com.package_rules <- List.fold_left forbid com.package_rules ("jvm" :: (List.map platform_name platforms));
 	com.config <- get_config com;
 	if com.config.pf_static then begin
 		raw_define_value com.defines "target.static" "true";
@@ -617,34 +623,81 @@ let platform ctx p = ctx.platform = p
 let platform_name_macro com =
 	if defined com Define.Macro then "macro" else platform_name com.platform
 
+let normalize_dir_separator path =
+	if is_windows then String.map (fun c -> if c = '/' then '\\' else c) path
+	else path
+
 let find_file ctx f =
 	try
-		(match Hashtbl.find ctx.file_lookup_cache f with
+		match Hashtbl.find ctx.file_lookup_cache f with
 		| None -> raise Exit
-		| Some f -> f)
+		| Some f -> f
 	with Exit ->
 		raise Not_found
 	| Not_found ->
+		let remove_extension file =
+			try String.sub file 0 (String.rindex file '.')
+			with Not_found -> file
+		in
+		let extension file =
+			try
+				let dot_pos = String.rindex file '.' in
+				String.sub file dot_pos (String.length file - dot_pos)
+			with Not_found -> file
+		in
+		let f_dir = Filename.dirname f
+		and platform_ext = "." ^ (platform_name_macro ctx)
+		and is_core_api = defined ctx Define.CoreApi in
 		let rec loop had_empty = function
 			| [] when had_empty -> raise Not_found
 			| [] -> loop true [""]
 			| p :: l ->
 				let file = p ^ f in
-				if Sys.file_exists file then begin
-					(try
-						let ext = String.rindex file '.' in
-						let file_pf = String.sub file 0 (ext + 1) ^ platform_name_macro ctx ^ String.sub file ext (String.length file - ext) in
-						if not (defined ctx Define.CoreApi) && Sys.file_exists file_pf then file_pf else file
-					with Not_found ->
-						file)
-				end else
+				let dir = Filename.dirname file in
+				if Hashtbl.mem ctx.readdir_cache (p,dir) then
 					loop (had_empty || p = "") l
+				else begin
+					let found = ref "" in
+					let dir_listing =
+						try Some (Sys.readdir dir);
+						with Sys_error _ -> None
+					in
+					Hashtbl.add ctx.readdir_cache (p,dir) dir_listing;
+					let normalized_f = normalize_dir_separator f in
+					Option.may
+						(Array.iter (fun file_name ->
+							let current_f = if f_dir = "." then file_name else f_dir ^ "/" ^ file_name in
+							let pf,current_f =
+								if is_core_api then false,current_f
+								else begin
+									let ext = extension current_f in
+									let pf_ext = extension (remove_extension current_f) in
+									if platform_ext = pf_ext then
+										true,(remove_extension (remove_extension current_f)) ^ ext
+									else
+										false,current_f
+								end
+							in
+							let is_cached = Hashtbl.mem ctx.file_lookup_cache current_f in
+							if is_core_api || pf || not is_cached then begin
+								let full_path = if dir = "." then file_name else dir ^ "/" ^ file_name in
+								if is_cached then
+									Hashtbl.remove ctx.file_lookup_cache current_f;
+								Hashtbl.add ctx.file_lookup_cache current_f (Some full_path);
+								if normalize_dir_separator current_f = normalized_f then
+									found := full_path;
+							end
+						))
+						dir_listing;
+					if !found <> "" then !found
+					else loop (had_empty || p = "") l
+				end
 		in
 		let r = (try Some (loop false ctx.class_path) with Not_found -> None) in
 		Hashtbl.add ctx.file_lookup_cache f r;
-		(match r with
+		match r with
 		| None -> raise Not_found
-		| Some f -> f)
+		| Some f -> f
 
 (* let find_file ctx f =
 	let timer = Timer.timer ["find_file"] in
@@ -759,4 +812,4 @@ let dump_context com = s_record_fields "" [
 	"class_path",s_list ", " (fun s -> s) com.class_path;
 	"defines",s_pmap (fun s -> s) (fun s -> s) com.defines.values;
 	"defines_signature",s_opt (fun s -> Digest.to_hex s) com.defines.defines_signature;
-]
+]

+ 78 - 1
src/context/compilationServer.ml

@@ -16,11 +16,18 @@ type cached_directory = {
 	mutable c_mtime : float;
 }
 
+type cached_native_lib = {
+	c_nl_mtime : float;
+	c_nl_files : (path,Ast.package) Hashtbl.t;
+}
+
 type cache = {
 	c_haxelib : (string list, string list) Hashtbl.t;
 	c_files : ((string * string), cached_file) Hashtbl.t;
 	c_modules : (path * string, module_def) Hashtbl.t;
 	c_directories : (string, cached_directory list) Hashtbl.t;
+	c_removed_files : (string * string,unit) Hashtbl.t;
+	c_native_libs : (string,cached_native_lib) Hashtbl.t;
 }
 
 type context_sign = {
@@ -46,6 +53,8 @@ let create_cache () = {
 	c_files = Hashtbl.create 0;
 	c_modules = Hashtbl.create 0;
 	c_directories = Hashtbl.create 0;
+	c_removed_files = Hashtbl.create 0;
+	c_native_libs = Hashtbl.create 0;
 }
 
 let create () =
@@ -119,6 +128,15 @@ let cache_module cs key value =
 let taint_modules cs file =
 	Hashtbl.iter (fun _ m -> if m.m_extra.m_file = file then m.m_extra.m_dirty <- Some m) cs.cache.c_modules
 
+let filter_modules cs file =
+	let removed = DynArray.create () in
+	(* TODO: Using filter_map_inplace would be better, but we can't move to OCaml 4.03 yet *)
+	Hashtbl.iter (fun k m ->
+		if m.m_extra.m_file = file then	DynArray.add removed (k,m);
+	) cs.cache.c_modules;
+	DynArray.iter (fun (k,_) -> Hashtbl.remove cs.cache.c_modules k) removed;
+	DynArray.to_list removed
+
 let iter_modules cs com f =
 	let sign = Define.get_signature com.defines in
 	Hashtbl.iter (fun (_,sign') m -> if sign = sign' then f m) cs.cache.c_modules
@@ -136,7 +154,10 @@ let cache_file cs key time data =
 	Hashtbl.replace cs.cache.c_files key { c_time = time; c_package = fst data; c_decls = snd data; c_module_name = None }
 
 let remove_file cs key =
-	Hashtbl.remove cs.cache.c_files key
+	if Hashtbl.mem cs.cache.c_files key then begin
+		Hashtbl.remove cs.cache.c_files key;
+		Hashtbl.replace cs.cache.c_removed_files key ()
+	end
 
 let remove_files cs file =
 	List.iter (fun (sign,_) -> remove_file cs (file,sign)) cs.signs
@@ -204,6 +225,62 @@ let add_directory cs key value =
 let clear_directories cs key =
 	Hashtbl.remove cs.cache.c_directories key
 
+(* native lib *)
+
+let add_native_lib cs key files timestamp =
+	Hashtbl.replace cs.cache.c_native_libs key { c_nl_files = files; c_nl_mtime = timestamp }
+
+let get_native_lib cs key =
+	try Some (Hashtbl.find cs.cache.c_native_libs key)
+	with Not_found -> None
+
+let handle_native_lib com lib =
+	com.native_libs.all_libs <- lib#get_file_path :: com.native_libs.all_libs;
+	com.load_extern_type <- com.load_extern_type @ [lib#get_file_path,lib#build];
+	match get() with
+	| Some cs when Define.raw_defined com.defines "haxe.cacheNativeLibs" ->
+		let init () =
+			let file = lib#get_file_path in
+			let key = file in
+			let ftime = file_time file in
+			begin match get_native_lib cs key with
+			| Some lib when ftime <= lib.c_nl_mtime ->
+				(* Cached lib is good, set up lookup into cached files. *)
+				lib.c_nl_files;
+			| _ ->
+				(* Cached lib is outdated or doesn't exist yet, read library. *)
+				lib#load;
+				(* Created lookup and eagerly read each known type. *)
+				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
+						try begin match lib#build path p with
+						| Some r -> Hashtbl.add h path r
+						| None -> ()
+						end with _ ->
+							()
+					end
+				) lib#list_modules;
+				(* Save and set up lookup. *)
+				add_native_lib cs key h ftime;
+				h;
+			end;
+		in
+		(fun () ->
+			let lut = init() in
+			let build path p =
+				try Some (Hashtbl.find lut path)
+				with Not_found -> None
+			in
+			com.load_extern_type <- List.map (fun (name,f) ->
+				name,if name = lib#get_file_path then build else f
+			) com.load_extern_type
+		)
+	| _ ->
+		(* Offline mode, just read library as usual. *)
+		(fun () -> lib#load)
+
 (* context *)
 
 let rec cache_context cs com =

+ 9 - 3
src/context/display/deprecationCheck.ml

@@ -9,8 +9,10 @@ let warned_positions = Hashtbl.create 0
 
 let warn_deprecation com s p_usage =
 	if not (Hashtbl.mem warned_positions p_usage) then begin
-		Hashtbl.replace warned_positions p_usage true;
-		com.warning s p_usage;
+		Hashtbl.replace warned_positions p_usage s;
+		match com.display.dms_kind with
+		| DMDiagnostics _ -> ()
+		| _ -> com.warning s p_usage;
 	end
 
 let print_deprecation_message com meta s p_usage =
@@ -63,7 +65,11 @@ let run_on_expr com e =
 		| TNew(c,_,el) ->
 			List.iter expr el;
 			check_class com c e.epos;
-			(match c.cl_constructor with None -> () | Some cf -> check_cf com cf e.epos)
+			begin match c.cl_constructor with
+				(* The AST doesn't carry the correct overload for TNew, so let's ignore this case... (#8557). *)
+				| Some cf when cf.cf_overloads = [] -> check_cf com cf e.epos
+				| _ -> ()
+			end
 		| TTypeExpr(mt) | TCast(_,Some mt) ->
 			check_module_type com mt e.epos
 		| TMeta((Meta.Deprecated,_,_) as meta,e1) ->

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

@@ -190,6 +190,9 @@ module Printer = struct
 		List.iter (fun (s,p,prange) ->
 			add DKRemovableCode p DiagnosticsSeverity.Warning (JObject ["description",JString s;"range",if prange = null_pos then JNull else Genjson.generate_pos_as_range prange])
 		) dctx.removable_code;
+		Hashtbl.iter (fun p s ->
+			add DKDeprecationWarning p DiagnosticsSeverity.Warning (JString s);
+		) DeprecationCheck.warned_positions;
 		let jl = Hashtbl.fold (fun file diag acc ->
 			let jl = Hashtbl.fold (fun _ (dk,p,sev,jargs) acc ->
 				(JObject [

+ 7 - 2
src/context/display/displayEmitter.ml

@@ -15,7 +15,12 @@ open Display
 open DisplayPosition
 
 let get_expected_name with_type = match with_type with
-	| WithType.Value (Some s) | WithType.WithType(_,Some s) -> Some s
+	| WithType.Value (Some src) | WithType.WithType(_,Some src) ->
+		(match src with
+		| WithType.FunctionArgument name -> Some name
+		| WithType.StructureField name -> Some name
+		| WithType.ImplicitReturn -> None
+		)
 	| _ -> None
 
 let sort_fields l with_type tk =
@@ -25,7 +30,7 @@ let sort_fields l with_type tk =
 	in
 	let expected_name = get_expected_name with_type in
 	let l = List.map (fun ci ->
-		let i = get_sort_index tk ci (Option.default Globals.null_pos p) (Option.map fst expected_name) in
+		let i = get_sort_index tk ci (Option.default Globals.null_pos p) expected_name in
 		ci,i
 	) l in
 	let sort l =

+ 95 - 18
src/context/display/displayException.ml

@@ -11,6 +11,13 @@ type hover_result = {
 	hexpected : WithType.t option;
 }
 
+type fields_result = {
+	fitems : CompletionItem.t list;
+	fkind : CompletionResultKind.t;
+	finsert_pos : pos option;
+	fsubject : placed_name option;
+}
+
 type signature_kind =
 	| SKCall
 	| SKArrayAccess
@@ -23,7 +30,7 @@ type kind =
 	| DisplaySignatures of (((tsignature * CompletionType.ct_function) * documentation) list * int * int * signature_kind) option
 	| DisplayHover of hover_result option
 	| DisplayPositions of pos list
-	| DisplayFields of (CompletionItem.t list * CompletionResultKind.t * pos option (* insert pos *)) option
+	| DisplayFields of fields_result option
 	| DisplayPackage of string list
 
 exception DisplayException of kind
@@ -35,17 +42,78 @@ let raise_metadata s = raise (DisplayException(Metadata s))
 let raise_signatures l isig iarg kind = raise (DisplayException(DisplaySignatures(Some(l,isig,iarg,kind))))
 let raise_hover item expected p = raise (DisplayException(DisplayHover(Some {hitem = item;hpos = p;hexpected = expected})))
 let raise_positions pl = raise (DisplayException(DisplayPositions pl))
-let raise_fields ckl cr po = raise (DisplayException(DisplayFields(Some(ckl,cr,po))))
+let raise_fields ckl cr po = raise (DisplayException(DisplayFields(Some({fitems = ckl;fkind = cr;finsert_pos = po;fsubject = None}))))
+let raise_fields2 ckl cr po subject = raise (DisplayException(DisplayFields(Some({fitems = ckl;fkind = cr;finsert_pos = po;fsubject = Some subject}))))
 let raise_package sl = raise (DisplayException(DisplayPackage sl))
 
 (* global state *)
 let last_completion_result = ref (Array.make 0 (CompletionItem.make (ITModule ([],"")) None))
+let last_completion_pos = ref None
+let max_completion_items = ref 0
 
-let fields_to_json ctx fields kind po =
-	let ja = List.map (CompletionItem.to_json ctx) fields in
+let filter_somehow ctx items subject kind po =
+	let ret = DynArray.create () in
+	let acc_types = DynArray.create () in
+	let subject = match subject with
+		| None -> ""
+		| Some(subject,_) -> String.lowercase subject
+	in
+	let subject_matches s =
+		let rec loop i o =
+			if i < String.length subject then begin
+				let o = String.index_from s o subject.[i] in
+				loop (i + 1) o
+			end
+		in
+		try
+			loop 0 0;
+			true
+		with Not_found ->
+			false
+	in
+	let rec loop items index =
+		match items with
+		| _ when DynArray.length ret > !max_completion_items ->
+			()
+		| item :: items ->
+			let name = String.lowercase (get_filter_name item) in
+			if subject_matches name then begin
+				(* Treat types with lowest priority. The assumption is that they are the only kind
+				   which actually causes the limit to be hit, so we show everything else and then
+				   fill in types. *)
+				match item.ci_kind with
+				| ITType _ ->
+					if DynArray.length ret + DynArray.length acc_types < !max_completion_items then
+						DynArray.add acc_types (item,index);
+				| _ ->
+					DynArray.add ret (CompletionItem.to_json ctx (Some index) item);
+			end;
+			loop items (index + 1)
+		| [] ->
+			()
+	in
+	loop items 0;
+	DynArray.iter (fun (item,index) ->
+		if DynArray.length ret < !max_completion_items then
+			DynArray.add ret (CompletionItem.to_json ctx (Some index) item);
+	) acc_types;
+	DynArray.to_list ret,DynArray.length ret = !max_completion_items
+
+let fields_to_json ctx fields kind po subject =
 	last_completion_result := Array.of_list fields;
+	let needs_filtering = !max_completion_items > 0 && Array.length !last_completion_result > !max_completion_items in
+	let ja,did_filter = if needs_filtering then
+		filter_somehow ctx fields subject kind po
+	else
+		List.mapi (fun i item -> CompletionItem.to_json ctx (Some i) item) fields,false
+ 	in
+	if did_filter then begin match subject with
+		| Some(_,p) -> last_completion_pos := Some p;
+		| None -> last_completion_pos := None
+	end;
 	let fl =
 		("items",jarray ja) ::
+		("isIncomplete",jbool did_filter) ::
 		("mode",CompletionResultKind.to_json ctx kind) ::
 		(match po with None -> [] | Some p -> ["replaceRange",generate_pos_as_range (Parser.cut_pos_at_display p)]) in
 	jobject fl
@@ -79,33 +147,42 @@ let to_json ctx de =
 	| DisplayHover None ->
 		jnull
 	| DisplayHover (Some hover) ->
-		let name_source_kind_to_int = function
-			| WithType.FunctionArgument -> 0
-			| WithType.StructureField -> 1
+		let named_source_kind = function
+			| WithType.FunctionArgument name -> (0, name)
+			| WithType.StructureField name -> (1, name)
+			| _ -> assert false
 		in
 		let ctx = Genjson.create_context GMFull in
-		let generate_name (name,kind) = jobject [
-			"name",jstring name;
-			"kind",jint (name_source_kind_to_int kind);
-		] in
+		let generate_name kind =
+			let i, name = named_source_kind kind in
+			jobject [
+				"name",jstring name;
+				"kind",jint i;
+			]
+		in
 		let expected = match hover.hexpected with
-			| Some(WithType.WithType(t,name)) ->
-				jobject (("type",generate_type ctx t) :: (match name with None -> [] | Some name -> ["name",generate_name name]))
-			| Some(Value(Some name)) ->
-				jobject ["name",generate_name name]
+			| Some(WithType.WithType(t,src)) ->
+				jobject (("type",generate_type ctx t)
+				:: (match src with
+					| None -> []
+					| Some ImplicitReturn -> []
+					| Some src -> ["name",generate_name src])
+				)
+			| Some(Value(Some ((FunctionArgument name | StructureField name) as src))) ->
+				jobject ["name",generate_name src]
 			| _ -> jnull
 		in
 		jobject [
 			"documentation",jopt jstring (CompletionItem.get_documentation hover.hitem);
 			"range",generate_pos_as_range hover.hpos;
-			"item",CompletionItem.to_json ctx hover.hitem;
+			"item",CompletionItem.to_json ctx None hover.hitem;
 			"expected",expected;
 		]
 	| DisplayPositions pl ->
 		jarray (List.map generate_pos_as_location pl)
 	| DisplayFields None ->
 		jnull
-	| DisplayFields Some(fields,kind,po) ->
-		fields_to_json ctx fields kind po
+	| DisplayFields Some r ->
+		fields_to_json ctx r.fitems r.fkind r.finsert_pos r.fsubject
 	| DisplayPackage pack ->
 		jarray (List.map jstring pack)

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

@@ -50,7 +50,7 @@ let collect_static_extensions ctx items e p =
 		| (c,_) :: l ->
 			let rec dup t = Type.map dup t in
 			let acc = List.fold_left (fun acc f ->
-				if Meta.has Meta.NoUsing f.cf_meta || Meta.has Meta.NoCompletion f.cf_meta || Meta.has Meta.Impl f.cf_meta || PMap.mem f.cf_name items then
+				if Meta.has Meta.NoUsing f.cf_meta || Meta.has Meta.NoCompletion f.cf_meta || Meta.has Meta.Impl f.cf_meta || PMap.mem f.cf_name acc then
 					acc
 				else begin
 					let f = { f with cf_type = opt_type f.cf_type } in
@@ -171,8 +171,11 @@ let collect ctx e_ast e dk with_type p =
 					| _ -> None
 				) el in
 				let forwarded_fields = loop PMap.empty (apply_params a.a_params tl a.a_this) in
+				let abstract_has_own_field field_name =
+					PMap.mem field_name c.cl_fields || PMap.mem field_name c.cl_statics
+				in
 				PMap.foldi (fun name item acc ->
-					if sl = [] || List.mem name sl && is_new_item acc name then
+					if (sl = [] || List.mem name sl && is_new_item acc name) && not (abstract_has_own_field name) then
 						PMap.add name item acc
 					else
 						acc

+ 14 - 2
src/context/display/displayJson.ml

@@ -87,6 +87,7 @@ let handler =
 	let l = [
 		"initialize", (fun hctx ->
 			supports_resolve := hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_bool_param "supportsResolve") false;
+			DisplayException.max_completion_items := hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_int_param "maxCompletionItems") 0;
 			let exclude = hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_array_param "exclude") [] in
 			DisplayToplevel.exclude := List.map (fun e -> match e with JString s -> s | _ -> assert false) exclude;
 			let methods = Hashtbl.fold (fun k _ acc -> (jstring k) :: acc) h [] in
@@ -111,7 +112,7 @@ let handler =
 			begin try
 				let item = (!DisplayException.last_completion_result).(i) in
 				let ctx = Genjson.create_context GMFull in
-				hctx.send_result (jobject ["item",CompletionItem.to_json ctx item])
+				hctx.send_result (jobject ["item",CompletionItem.to_json ctx None item])
 			with Invalid_argument _ ->
 				hctx.send_error [jstring (Printf.sprintf "Invalid index: %i" i)]
 			end
@@ -179,6 +180,15 @@ let handler =
 			in
 			hctx.send_result (generate_module () m)
 		);
+		"server/moduleCreated", (fun hctx ->
+			let file = hctx.jsonrpc#get_string_param "file" in
+			let file = Path.unique_full_path file in
+			let cs = hctx.display#get_cs in
+			List.iter (fun (sign,_) ->
+				Hashtbl.replace cs.cache.c_removed_files (file,sign) ()
+			) (CompilationServer.get_signs cs);
+			hctx.send_result (jstring file);
+		);
 		"server/files", (fun hctx ->
 			let sign = Digest.from_hex (hctx.jsonrpc#get_string_param "signature") in
 			let files = CompilationServer.get_files hctx.display#get_cs in
@@ -196,7 +206,9 @@ let handler =
 		"server/invalidate", (fun hctx ->
 			let file = hctx.jsonrpc#get_string_param "file" in
 			let file = Path.unique_full_path file in
-			CompilationServer.taint_modules hctx.display#get_cs file;
+			let cs = hctx.display#get_cs in
+			CompilationServer.taint_modules cs file;
+			CompilationServer.remove_files cs file;
 			hctx.send_result jnull
 		);
 		"server/configure", (fun hctx ->

+ 54 - 12
src/context/display/displayToplevel.ml

@@ -84,6 +84,27 @@ let read_class_paths com timer =
 			()
 	)
 
+let init_or_update_server cs com timer_name =
+	if not (CompilationServer.is_initialized cs) then begin
+		CompilationServer.set_initialized cs;
+		read_class_paths com timer_name
+	end else begin
+		(* Iterate all removed files of the current context. If they aren't part of the context again,
+		   re-parse them and remove them from c_removed_files. *)
+		let sign = Define.get_signature com.defines in
+		let removed_removed_files = DynArray.create () in
+		Hashtbl.iter (fun (file,sign') () ->
+			if sign = sign' then begin
+				DynArray.add removed_removed_files (file,sign');
+				try
+					ignore(find_file cs (file,sign));
+				with Not_found ->
+					try ignore(TypeloadParse.parse_module_file com file null_pos) with _ -> ()
+			end;
+		) cs.cache.c_removed_files;
+		DynArray.iter (Hashtbl.remove cs.cache.c_removed_files) removed_removed_files;
+	end
+
 module CollectionContext = struct
 	open ImportStatus
 
@@ -175,6 +196,11 @@ let collect ctx tk with_type =
 	in
 
 	let process_decls pack name decls =
+		let added_something = ref false in
+		let add item name =
+			added_something := true;
+			add item name
+		in
 		let run () = List.iter (fun (d,p) ->
 			begin try
 				let tname,is_private,meta = match d with
@@ -197,7 +223,8 @@ let collect ctx tk with_type =
 				()
 			end
 		) decls in
-		if is_pack_visible pack then run()
+		if is_pack_visible pack then run();
+		!added_something
 	in
 
 	(* Collection starts here *)
@@ -362,15 +389,12 @@ let collect ctx tk with_type =
 		explore_class_paths ctx.com ["display";"toplevel"] class_paths true add_package (fun path ->
 			if not (path_exists cctx path) then begin
 				let _,decls = Display.parse_module ctx path Globals.null_pos in
-				process_decls (fst path) (snd path) decls
+				ignore(process_decls (fst path) (snd path) decls)
 			end
 		)
 	| Some cs ->
 		(* online: iter context files *)
-		if not (CompilationServer.is_initialized cs) then begin
-			CompilationServer.set_initialized cs;
-			read_class_paths ctx.com ["display";"toplevel"];
-		end;
+		init_or_update_server cs ctx.com ["display";"toplevel"];
 		let files = CompilationServer.get_file_list cs ctx.com in
 		(* Sort files by reverse distance of their package to our current package. *)
 		let files = List.map (fun (file,cfile) ->
@@ -378,20 +402,29 @@ let collect ctx tk with_type =
 			(file,cfile),i
 		) files in
 		let files = List.sort (fun (_,i1) (_,i2) -> -compare i1 i2) files in
+		let check_package pack = match List.rev pack with
+			| [] -> ()
+			| s :: sl -> add_package (List.rev sl,s)
+		in
 		List.iter (fun ((file,cfile),_) ->
 			let module_name = CompilationServer.get_module_name_of_cfile file cfile in
 			let dot_path = s_type_path (cfile.c_package,module_name) in
 			if (List.exists (fun e -> ExtString.String.starts_with dot_path (e ^ ".")) !exclude) then
 				()
 			else begin
-				begin match List.rev cfile.c_package with
-					| [] -> ()
-					| s :: sl -> add_package (List.rev sl,s)
-				end;
 				Hashtbl.replace ctx.com.module_to_file (cfile.c_package,module_name) file;
-				process_decls cfile.c_package module_name cfile.c_decls
+				if process_decls cfile.c_package module_name cfile.c_decls then check_package cfile.c_package;
 			end
-		) files
+		) files;
+		List.iter (fun file ->
+			try
+				let lib = Hashtbl.find cs.cache.c_native_libs file in
+				Hashtbl.iter (fun path (pack,decls) ->
+					if process_decls pack (snd path) decls then check_package pack;
+				) lib.c_nl_files
+			with Not_found ->
+				()
+		) ctx.com.native_libs.all_libs
 	end;
 
 	(* packages *)
@@ -406,6 +439,15 @@ let collect ctx tk with_type =
 	t();
 	l
 
+let collect_and_raise ctx tk with_type cr subject pinsert =
+	let fields = match !DisplayException.last_completion_pos with
+	| Some p' when (pos subject).pmin = p'.pmin ->
+		Array.to_list (!DisplayException.last_completion_result)
+	| _ ->
+		collect ctx tk with_type
+	in
+	DisplayException.raise_fields2 fields cr pinsert subject
+
 let handle_unresolved_identifier ctx i p only_types =
 	let l = collect ctx (if only_types then TKType else TKExpr p) NoValue in
 	let cl = List.map (fun it ->

+ 1 - 4
src/context/display/findReferences.ml

@@ -148,10 +148,7 @@ let find_possible_references kind name (pack,decls) =
 
 let find_possible_references tctx cs =
 	let name,pos,kind = Display.ReferencePosition.get () in
-	if not (CompilationServer.is_initialized cs) then begin
-		CompilationServer.set_initialized cs;
-		DisplayToplevel.read_class_paths tctx.com ["display";"references"];
-	end;
+	DisplayToplevel.init_or_update_server cs tctx.com ["display";"references"];
 	let files = CompilationServer.get_file_list cs tctx.com in
 	let t = Timer.timer ["display";"references";"candidates"] in
 	List.iter (fun (file,cfile) ->

+ 60 - 0
src/context/nativeLibraries.ml

@@ -0,0 +1,60 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
+open Globals
+open ExtString
+
+type native_lib_flags =
+	| FlagIsStd
+	| FlagIsExtern
+
+class virtual ['a,'data] native_library (name : string) (file_path : string) = object(self)
+	val mutable flags : native_lib_flags list = []
+
+	method add_flag flag = flags <- flag :: flags
+	method has_flag flag = List.mem flag flags
+
+	method get_name = name
+	method get_file_path = file_path
+
+	method virtual build : path -> pos -> Ast.package option
+	method virtual close : unit
+	method virtual list_modules : path list
+	method virtual load : unit
+	method virtual lookup : path -> 'a
+	method virtual get_data : 'data
+end
+
+type java_lib_type = (JData.jclass * string * string) option
+type net_lib_type = IlData.ilclass option
+type swf_lib_type = As3hl.hl_class option
+
+type native_libraries = {
+	mutable java_libs : (java_lib_type,unit) native_library list;
+	mutable net_libs : (net_lib_type,unit) native_library list;
+	mutable swf_libs : (swf_lib_type,Swf.swf) native_library list;
+	mutable all_libs : string list;
+}
+
+let create_native_libs () = {
+	java_libs = [];
+	net_libs = [];
+	swf_libs = [];
+	all_libs = [];
+}

+ 39 - 0
src/context/nativeLibraryHandler.ml

@@ -0,0 +1,39 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
+open Globals
+open Common
+
+let add_native_lib com file is_extern = match com.platform with
+	| Globals.Flash ->
+		SwfLoader.add_swf_lib com file is_extern
+	| Globals.Java ->
+		let std = file = "lib/hxjava-std.jar" in
+		Java.add_java_lib com file std is_extern
+	| Globals.Cs ->
+		let file, is_std = match ExtString.String.nsplit file "@" with
+			| [file] ->
+				file,false
+			| [file;"std"] ->
+				file,true
+			| _ -> failwith ("unsupported file@`std` format: " ^ file)
+		in
+		Dotnet.add_net_lib com file is_std is_extern
+	| pf ->
+		failwith (Printf.sprintf "Target %s does not support native libraries (trying to load %s)" (platform_name pf) file);

+ 9 - 2
src/context/typecore.ml

@@ -44,6 +44,11 @@ type macro_mode =
 	| MMacroType
 	| MDisplay
 
+type access_mode =
+	| MGet
+	| MSet
+	| MCall
+
 type typer_pass =
 	| PBuildModule			(* build the module structure and setup module type parameters *)
 	| PBuildClass			(* build the class structure *)
@@ -133,9 +138,10 @@ exception Forbid_package of (string * path * pos) * pos list * string
 exception WithTypeError of error_msg * pos
 
 let make_call_ref : (typer -> texpr -> texpr list -> t -> ?force_inline:bool -> pos -> texpr) ref = ref (fun _ _ _ _ ?force_inline:bool _ -> assert false)
-let type_expr_ref : (typer -> expr -> WithType.t -> texpr) ref = ref (fun _ _ _ -> assert false)
+let type_expr_ref : (?mode:access_mode -> typer -> expr -> WithType.t -> texpr) ref = ref (fun ?(mode=MGet) _ _ _ -> assert false)
 let type_block_ref : (typer -> expr list -> WithType.t -> pos -> texpr) ref = ref (fun _ _ _ _ -> assert false)
 let unify_min_ref : (typer -> texpr list -> t) ref = ref (fun _ _ -> assert false)
+let unify_min_for_type_source_ref : (typer -> texpr list -> WithType.with_type_source option -> t) ref = ref (fun _ _ _ -> assert false)
 let analyzer_run_on_expr_ref : (Common.context -> texpr -> texpr) ref = ref (fun _ _ -> assert false)
 
 let pass_name = function
@@ -153,9 +159,10 @@ let display_error ctx msg p = match ctx.com.display.DisplayMode.dms_error_policy
 
 let make_call ctx e el t p = (!make_call_ref) ctx e el t p
 
-let type_expr ctx e with_type = (!type_expr_ref) ctx e with_type
+let type_expr ?(mode=MGet) ctx e with_type = (!type_expr_ref) ~mode ctx e with_type
 
 let unify_min ctx el = (!unify_min_ref) ctx el
+let unify_min_for_type_source ctx el src = (!unify_min_for_type_source_ref) ctx el src
 
 let make_static_this c p =
 	let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in

+ 12 - 2
src/core/abstract.ml

@@ -49,7 +49,7 @@ let find_from ab pl a b =
 
 let underlying_type_stack = new_rec_stack()
 
-let rec get_underlying_type a pl =
+let rec get_underlying_type ?(return_first=false) a pl =
 	let maybe_recurse t =
 		let rec loop t = match t with
 			| TMono r ->
@@ -68,7 +68,13 @@ let rec get_underlying_type a pl =
 					let s = String.concat " -> " (List.map (fun t -> s_type pctx t) (List.rev (t :: underlying_type_stack.rec_stack))) in
 					error ("Abstract chain detected: " ^ s) a.a_pos
 				end;
-				get_underlying_type a tl
+				(*
+					Even if only the first underlying type was requested
+					keep traversing to detect mutually recursive abstracts
+				*)
+				let result = get_underlying_type a tl in
+				if return_first then t
+				else result
 			| _ ->
 				t
 		in
@@ -76,6 +82,10 @@ let rec get_underlying_type a pl =
 	in
 	try
 		if not (Meta.has Meta.MultiType a.a_meta) then raise Not_found;
+		(* TODO:
+			Look into replacing `mk_mono` & `find_to` with `build_abstract a` & `TAbstract(a, pl)`.
+			`find_to` is probably needed for `@:multiType`
+		*)
 		let m = mk_mono() in
 		let _ = find_to a pl m in
 		maybe_recurse (follow m)

+ 9 - 4
src/core/define.ml

@@ -12,14 +12,19 @@ let get_documentation_list() =
 		let d = Obj.magic i in
 		if d <> Last then begin
 			let t, (doc,flags) = infos d in
-			let pfs = ref [] in
+			let params = ref [] and pfs = ref [] in
 			List.iter (function
-			| HasParam s -> () (* TODO *)
-			| Platforms pl -> pfs := pl @ !pfs;
+				| HasParam s -> params := s :: !params
+				| Platforms fl -> pfs := fl @ !pfs
+				| Link _ -> ()
 			) flags;
+			let params = (match List.rev !params with
+				| [] -> ""
+				| l -> "<" ^ String.concat ">, <" l ^ "> "
+			) in
 			let pfs = platform_list_help (List.rev !pfs) in
 			if String.length t > !m then m := String.length t;
-			((String.concat "-" (ExtString.String.nsplit t "_")),doc ^ pfs) :: (loop (i + 1))
+			((String.concat "-" (ExtString.String.nsplit t "_")),params ^ doc ^ pfs) :: (loop (i + 1))
 		end else
 			[]
 	in

+ 35 - 9
src/core/display/completionItem.ml

@@ -567,13 +567,28 @@ let get_name item = match item.ci_kind with
 
 let get_type item = item.ci_type
 
+let get_filter_name item = match item.ci_kind with
+	| ITLocal v -> v.v_name
+	| ITClassField(cf) | ITEnumAbstractField(_,cf) -> cf.field.cf_name
+	| ITEnumField ef -> ef.efield.ef_name
+	| ITType(cm,_) -> s_type_path (cm.pack,cm.name)
+	| ITPackage(path,_) -> s_type_path path
+	| ITModule path -> s_type_path path
+	| ITLiteral s -> s
+	| ITTimer(s,_) -> s
+	| ITMetadata meta -> Meta.to_string meta
+	| ITKeyword kwd -> s_keyword kwd
+	| ITAnonymous _ -> ""
+	| ITExpression _ -> ""
+	| ITTypeParameter c -> snd c.cl_path
+
 let get_documentation item = match item.ci_kind with
 	| ITClassField cf | ITEnumAbstractField(_,cf) -> cf.field.cf_doc
 	| ITEnumField ef -> ef.efield.ef_doc
 	| ITType(mt,_) -> mt.doc
 	| _ -> None
 
-let to_json ctx item =
+let to_json ctx index item =
 	let open ClassFieldOrigin in
 	let kind,data = match item.ci_kind with
 		| ITLocal v -> "Local",generate_tvar ctx v
@@ -653,14 +668,15 @@ let to_json ctx item =
 				| TTypeParameter -> "TTypeParameter"
 				| TVariable -> "TVariable"
 			in
-			let rec loop internal params platforms targets l = match l with
-				| HasParam s :: l -> loop internal (s :: params) platforms targets l
-				| Platforms pls :: l -> loop internal params ((List.map platform_name pls) @ platforms) targets l
-				| UsedOn usages :: l -> loop internal params platforms ((List.map usage_to_string usages) @ targets) l
-				| UsedInternally :: l -> loop true params platforms targets l
-				| [] -> internal,params,platforms,targets
+			let rec loop internal params platforms targets links l = match l with
+				| HasParam s :: l -> loop internal (s :: params) platforms targets links l
+				| Platforms pls :: l -> loop internal params ((List.map platform_name pls) @ platforms) targets links l
+				| UsedOn usages :: l -> loop internal params platforms ((List.map usage_to_string usages) @ targets) links l
+				| UsedInternally :: l -> loop true params platforms targets links l
+				| Link url :: l -> loop internal params platforms targets (url :: links) l
+				| [] -> internal,params,platforms,targets,links
 			in
-			let internal,params,platforms,targets = loop false [] [] [] params in
+			let internal,params,platforms,targets,links = loop false [] [] [] [] params in
 			"Metadata",jobject [
 				"name",jstring name;
 				"doc",jstring doc;
@@ -668,6 +684,7 @@ let to_json ctx item =
 				"platforms",jlist jstring platforms;
 				"targets",jlist jstring targets;
 				"internal",jbool internal;
+				"links",jlist jstring links;
 			]
 		| ITKeyword kwd ->"Keyword",jobject [
 			"name",jstring (s_keyword kwd)
@@ -685,8 +702,17 @@ let to_json ctx item =
 			| _ -> assert false
 			end
 	in
+	let jindex = match index with
+		| None -> []
+		| Some index -> ["index",jint index]
+	in
 	jobject (
 		("kind",jstring kind) ::
 		("args",data) ::
-		(match item.ci_type with None -> [] | Some t -> ["type",CompletionType.to_json ctx (snd t)])
+		(match item.ci_type with
+			| None ->
+				jindex
+			| Some t ->
+				("type",CompletionType.to_json ctx (snd t)) :: jindex
+		)
 	)

+ 3 - 1
src/core/displayTypes.ml

@@ -70,6 +70,7 @@ module DiagnosticsKind = struct
 		| DKCompilerError
 		| DKRemovableCode
 		| DKParserError
+		| DKDeprecationWarning
 
 	let to_int = function
 		| DKUnusedImport -> 0
@@ -77,6 +78,7 @@ module DiagnosticsKind = struct
 		| DKCompilerError -> 2
 		| DKRemovableCode -> 3
 		| DKParserError -> 4
+		| DKDeprecationWarning -> 5
 end
 
 module CompletionResultKind = struct
@@ -123,7 +125,7 @@ module CompletionResultKind = struct
 							None
 				in
 				let fields =
-					("item",CompletionItem.to_json ctx item) ::
+					("item",CompletionItem.to_json ctx None item) ::
 					("range",generate_pos_as_range p) ::
 					("iterator", match iterator with
 						| None -> jnull

+ 3 - 1
src/core/error.ml

@@ -289,4 +289,6 @@ let error_require r p =
 	with _ ->
 		"'" ^ r ^ "' to be enabled"
 	in
-	error ("Accessing this field requires " ^ r) p
+	error ("Accessing this field requires " ^ r) p
+
+let invalid_assign p = error "Invalid assign" p

+ 1 - 0
src/core/globals.ml

@@ -8,6 +8,7 @@ type path = string list * string
 
 module IntMap = Ptmap
 module StringMap = Map.Make(struct type t = string let compare = String.compare end)
+module Int32Map = Map.Make(struct type t = Int32.t let compare = Int32.compare end)
 
 type platform =
 	| Cross

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

@@ -519,7 +519,12 @@ and generate_class_field' ctx cfs cf =
 						None
 			in
 			begin match value with
-				| None -> jnull
+				| None ->
+					if Meta.has (Meta.Custom ":testHack") cf.cf_meta then begin match cf.cf_expr with
+						| Some e -> jobject ["testHack",jstring (s_expr_pretty false "" false (s_type (print_context())) e)] (* TODO: haha *)
+						| None -> jnull
+					end else
+						jnull
 				| Some e -> jobject ["string",jstring (Ast.Printer.s_expr e)]
 			end
 		| GMMinimum ->

+ 2 - 1
src/core/meta.ml

@@ -41,10 +41,11 @@ let get_documentation d =
 			| Platforms fl -> pfs := fl @ !pfs
 			| UsedOn ul -> used := ul @ !used
 			| UsedInternally -> assert false
+			| Link _ -> ()
 		) flags;
 		let params = (match List.rev !params with
 			| [] -> ""
-			| l -> "(" ^ String.concat "," l ^ ")"
+			| l -> "(<" ^ String.concat ">, <" l ^ ">) "
 		) in
 		let pfs = platform_list_help (List.rev !pfs) in
 		let str = "@" ^ t in

+ 142 - 23
src/core/type.ml

@@ -634,7 +634,7 @@ let map loop t =
 	| TDynamic t2 ->
 		if t == t2 then	t else TDynamic (loop t2)
 
-let dup t =
+let duplicate t =
 	let monos = ref [] in
 	let rec loop t =
 		match t with
@@ -650,8 +650,10 @@ let dup t =
 	in
 	loop t
 
+exception ApplyParamsRecursion
+
 (* substitute parameters with other types *)
-let apply_params cparams params t =
+let apply_params ?stack cparams params t =
 	match cparams with
 	| [] -> t
 	| _ ->
@@ -679,7 +681,52 @@ let apply_params cparams params t =
 		| TType (t2,tl) ->
 			(match tl with
 			| [] -> t
-			| _ -> TType (t2,List.map loop tl))
+			| _ ->
+				let new_applied_params = List.map loop tl in
+				(match stack with
+				| None -> ()
+				| Some stack ->
+					List.iter (fun (subject, old_applied_params) ->
+						(*
+							E.g.:
+							```
+							typedef Rec<T> = { function method():Rec<Array<T>> }
+							```
+							We need to make sure that we are not applying the result of previous
+							application to the same place, which would mean the result of current
+							application would go into `apply_params` again and then again and so on.
+
+							Argument `stack` holds all previous results of `apply_params` to typedefs in current
+							unification process.
+
+							Imagine we are trying to unify `Rec<Int>` with something.
+
+							Once `apply_params Array<T> Int Rec<Array<T>>` is called for the first time the result
+							will be `Rec< Array<Int> >`. Store `Array<Int>` into `stack`
+
+							Then the next params application looks like this:
+								`apply_params Array<T> Array<Int> Rec<Array<T>>`
+							Notice the second argument is actually the result of a previous `apply_params` call.
+							And the result of the current call is `Rec< Array<Array<Int>> >`.
+
+							The third call would be:
+								`apply_params Array<T> Array<Array<Int>> Rec<Array<T>>`
+							and so on.
+
+							To stop infinite params application we need to check that we are trying to apply params
+							produced by the previous `apply_params Array<Int> _ Rec<Array<T>>` to the same `Rec<Array<T>>`
+						*)
+						if
+							subject == t (* Check the place that we're applying to is the same `Rec<Array<T>>` *)
+							&& old_applied_params == params (* Check that params we're applying are the same params
+																produced by the previous call to
+																`apply_params Array<T> _ Rec<Array<T>>` *)
+						then
+							raise ApplyParamsRecursion
+					) !stack;
+					stack := (t, new_applied_params) :: !stack;
+				);
+				TType (t2,new_applied_params))
 		| TAbstract (a,tl) ->
 			(match tl with
 			| [] -> t
@@ -731,6 +778,21 @@ let apply_params cparams params t =
 let monomorphs eparams t =
 	apply_params eparams (List.map (fun _ -> mk_mono()) eparams) t
 
+let apply_params_stack = ref []
+
+let try_apply_params_rec cparams params t success =
+	let old_stack = !apply_params_stack in
+	try
+		let result = success (apply_params ~stack:apply_params_stack cparams params t) in
+		apply_params_stack := old_stack;
+		result
+	with
+		| ApplyParamsRecursion ->
+			apply_params_stack := old_stack;
+		| err ->
+			apply_params_stack := old_stack;
+			raise err
+
 let rec follow t =
 	match t with
 	| TMono r ->
@@ -1662,47 +1724,94 @@ let rec link e a b =
 		true
 	end
 
+let would_produce_recursive_anon field_acceptor field_donor =
+	try
+		(match !(field_acceptor.a_status) with
+		| Opened ->
+			PMap.iter (fun n field ->
+				match follow field.cf_type with
+				| TAnon a when field_acceptor == a -> raise Exit
+				| _ -> ()
+			) field_donor.a_fields;
+		| _ -> ());
+		false
+	with Exit -> true
+
 let link_dynamic a b = match follow a,follow b with
 	| TMono r,TDynamic _ -> r := Some b
 	| TDynamic _,TMono r -> r := Some a
 	| _ -> ()
 
-let rec fast_eq a b =
+let fast_eq_check type_param_check a b =
 	if a == b then
 		true
 	else match a , b with
 	| TFun (l1,r1) , TFun (l2,r2) when List.length l1 = List.length l2 ->
-		List.for_all2 (fun (_,_,t1) (_,_,t2) -> fast_eq t1 t2) l1 l2 && fast_eq r1 r2
+		List.for_all2 (fun (_,_,t1) (_,_,t2) -> type_param_check t1 t2) l1 l2 && type_param_check r1 r2
 	| TType (t1,l1), TType (t2,l2) ->
-		t1 == t2 && List.for_all2 fast_eq l1 l2
+		t1 == t2 && List.for_all2 type_param_check l1 l2
 	| TEnum (e1,l1), TEnum (e2,l2) ->
-		e1 == e2 && List.for_all2 fast_eq l1 l2
+		e1 == e2 && List.for_all2 type_param_check l1 l2
 	| TInst (c1,l1), TInst (c2,l2) ->
-		c1 == c2 && List.for_all2 fast_eq l1 l2
+		c1 == c2 && List.for_all2 type_param_check l1 l2
 	| TAbstract (a1,l1), TAbstract (a2,l2) ->
-		a1 == a2 && List.for_all2 fast_eq l1 l2
+		a1 == a2 && List.for_all2 type_param_check l1 l2
 	| _ , _ ->
 		false
 
+let rec fast_eq a b = fast_eq_check fast_eq a b
+
 let rec fast_eq_mono ml a b =
-	if a == b then
+	if fast_eq_check (fast_eq_mono ml) a b then
 		true
 	else match a , b with
-	| TFun (l1,r1) , TFun (l2,r2) when List.length l1 = List.length l2 ->
-		List.for_all2 (fun (_,_,t1) (_,_,t2) -> fast_eq_mono ml t1 t2) l1 l2 && fast_eq_mono ml r1 r2
-	| TType (t1,l1), TType (t2,l2) ->
-		t1 == t2 && List.for_all2 (fast_eq_mono ml) l1 l2
-	| TEnum (e1,l1), TEnum (e2,l2) ->
-		e1 == e2 && List.for_all2 (fast_eq_mono ml) l1 l2
-	| TInst (c1,l1), TInst (c2,l2) ->
-		c1 == c2 && List.for_all2 (fast_eq_mono ml) l1 l2
-	| TAbstract (a1,l1), TAbstract (a2,l2) ->
-		a1 == a2 && List.for_all2 (fast_eq_mono ml) l1 l2
 	| TMono _, _ ->
 		List.memq a ml
 	| _ , _ ->
 		false
 
+let rec fast_eq_anon ?(mono_equals_dynamic=false) a b =
+	if fast_eq_check (fast_eq_anon ~mono_equals_dynamic) a b then
+		true
+	else match a , b with
+	(*
+		`mono_equals_dynamic` is here because of https://github.com/HaxeFoundation/haxe/issues/8588#issuecomment-520138371
+		Generally unbound monomorphs should not be considered equal to anything,
+		because it's unknown, which types they would be bound to.
+	*)
+	| t, TMono { contents = None } when t == t_dynamic -> mono_equals_dynamic
+	| TMono { contents = None }, t when t == t_dynamic -> mono_equals_dynamic
+	| TMono { contents = Some t1 }, TMono { contents = Some t2 } ->
+		fast_eq_anon t1 t2
+	| TAnon a1, TAnon a2 ->
+		let fields_eq() =
+			let rec loop fields1 fields2 =
+				match fields1, fields2 with
+				| [], [] -> true
+				| _, [] | [], _ -> false
+				| f1 :: rest1, f2 :: rest2 ->
+					f1.cf_name = f2.cf_name
+					&& (try fast_eq_anon f1.cf_type f2.cf_type with Not_found -> false)
+					&& loop rest1 rest2
+			in
+			let fields1 = PMap.fold (fun field fields -> field :: fields) a1.a_fields []
+			and fields2 = PMap.fold (fun field fields -> field :: fields) a2.a_fields []
+			and sort_compare f1 f2 = compare f1.cf_name f2.cf_name in
+			loop (List.sort sort_compare fields1) (List.sort sort_compare fields2)
+		in
+		(match !(a2.a_status), !(a1.a_status) with
+		| Statics c, Statics c2 -> c == c2
+		| EnumStatics e, EnumStatics e2 -> e == e2
+		| AbstractStatics a, AbstractStatics a2 -> a == a2
+		| Extend tl1, Extend tl2 -> fields_eq() && List.for_all2 fast_eq_anon tl1 tl2
+		| Closed, Closed -> fields_eq()
+		| Opened, Opened -> fields_eq()
+		| Const, Const -> fields_eq()
+		| _ -> false
+		)
+	| _ , _ ->
+		false
+
 (* perform unification with subtyping.
    the first type is always the most down in the class hierarchy
    it's also the one that is pointed by the position.
@@ -1902,6 +2011,7 @@ let rec type_eq param a b =
 			| AbstractStatics a -> (match !(a1.a_status) with AbstractStatics a2 when a == a2 -> () | _ -> error [])
 			| _ -> ()
 			);
+			if would_produce_recursive_anon a1 a2 || would_produce_recursive_anon a2 a1 then error [cannot_unify a b];
 			PMap.iter (fun n f1 ->
 				try
 					let f2 = PMap.find n a2.a_fields in
@@ -1988,12 +2098,12 @@ let rec unify a b =
 	| TType (t,tl) , _ ->
 		rec_stack unify_stack (a,b)
 			(fun(a2,b2) -> fast_eq a a2 && fast_eq b b2)
-			(fun() -> unify (apply_params t.t_params tl t.t_type) b)
+			(fun() -> try_apply_params_rec t.t_params tl t.t_type (fun a -> unify a b))
 			(fun l -> error (cannot_unify a b :: l))
 	| _ , TType (t,tl) ->
 		rec_stack unify_stack (a,b)
 			(fun(a2,b2) -> fast_eq a a2 && fast_eq b b2)
-			(fun() -> unify a (apply_params t.t_params tl t.t_type))
+			(fun() -> try_apply_params_rec t.t_params tl t.t_type (unify a))
 			(fun l -> error (cannot_unify a b :: l))
 	| TEnum (ea,tl1) , TEnum (eb,tl2) ->
 		if ea != eb then error [cannot_unify a b];
@@ -2240,6 +2350,7 @@ and unify_abstracts a b a1 tl1 a2 tl2 =
 			error [cannot_unify a b]
 
 and unify_anons a b a1 a2 =
+	if would_produce_recursive_anon a1 a2 then error [cannot_unify a b];
 	(try
 		PMap.iter (fun n f2 ->
 		try
@@ -2251,7 +2362,11 @@ and unify_anons a b a1 a2 =
 				| _ -> error [invalid_kind n f1.cf_kind f2.cf_kind]);
 			if (has_class_field_flag f2 CfPublic) && not (has_class_field_flag f1 CfPublic) then error [invalid_visibility n];
 			try
-				unify_with_access f1 (field_type f1) f2;
+				let f1_type =
+					if fast_eq f1.cf_type f2.cf_type then f1.cf_type
+					else field_type f1
+				in
+				unify_with_access f1 f1_type f2;
 				(match !(a1.a_status) with
 				| Statics c when not (Meta.has Meta.MaybeUsed f1.cf_meta) -> f1.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: f1.cf_meta
 				| _ -> ());
@@ -2824,6 +2939,10 @@ module TExprToExpr = struct
 end
 
 module ExtType = struct
+	let is_mono = function
+		| TMono { contents = None } -> true
+		| _ -> false
+
 	let is_void = function
 		| TAbstract({a_path=[],"Void"},_) -> true
 		| _ -> false

+ 15 - 15
src/core/withType.ml

@@ -1,31 +1,31 @@
 open Type
 
-type expected_name_source =
-	| FunctionArgument
-	| StructureField
-
-type expected_name = string * expected_name_source
+type with_type_source =
+	| FunctionArgument of string
+	| StructureField of string
+	| ImplicitReturn
 
 type t =
 	| NoValue
-	| Value of expected_name option
-	| WithType of Type.t * expected_name option
+	| Value of with_type_source option
+	| WithType of Type.t * with_type_source option
 
 let with_type t = WithType(t,None)
-let with_argument t name = WithType(t,Some(name,FunctionArgument))
-let with_structure_field t name = WithType(t,Some(name,StructureField))
+let of_implicit_return t = WithType(t,Some ImplicitReturn)
+let with_argument t name = WithType(t,Some(FunctionArgument name))
+let with_structure_field t name = WithType(t,Some(StructureField name))
 let value = Value None
-let named_argument name = Value (Some(name,FunctionArgument))
-let named_structure_field name = Value (Some(name,StructureField))
+let named_argument name = Value (Some(FunctionArgument name))
+let named_structure_field name = Value (Some(StructureField name))
 let no_value = NoValue
 
 let to_string = function
 	| NoValue -> "NoValue"
-	| Value None -> "Value"
-	| Value (Some(s,_)) -> "Value " ^ s
+	| Value (None | Some ImplicitReturn) -> "Value"
+	| Value (Some(FunctionArgument s | StructureField s)) -> "Value " ^ s
 	| WithType(t,s) ->
 		let name = match s with
-			| None -> "None"
-			| Some(s,_) -> s
+			| Some(FunctionArgument s | StructureField s) -> s
+			| _ -> "None"
 		in
 		Printf.sprintf "WithType(%s, %s)" (s_type (print_context()) t) name

+ 74 - 22
src/filters/filters.ml

@@ -25,23 +25,7 @@ open Error
 open Globals
 open FiltersCommon
 
-(** retrieve string from @:native metadata or raise Not_found *)
-let get_native_name meta =
-	let rec get_native meta = match meta with
-		| [] -> raise Not_found
-		| (Meta.Native,[v],p as meta) :: _ ->
-			meta
-		| _ :: meta ->
-			get_native meta
-	in
-	let (_,e,mp) = get_native meta in
-	match e with
-	| [Ast.EConst (Ast.String name),p] ->
-		name,p
-	| [] ->
-		raise Not_found
-	| _ ->
-		error "String expected" mp
+let get_native_name = TypeloadCheck.get_native_name
 
 (* PASS 1 begin *)
 
@@ -365,12 +349,57 @@ let check_unification ctx e t =
 	end;
 	e
 
+let rec fix_return_dynamic_from_void_function ctx return_is_void e =
+	match e.eexpr with
+	| TFunction fn ->
+		let is_void = ExtType.is_void (follow fn.tf_type) in
+		let body = fix_return_dynamic_from_void_function ctx is_void fn.tf_expr in
+		{ e with eexpr = TFunction { fn with tf_expr = body } }
+	| TReturn (Some return_expr) when return_is_void && t_dynamic == follow return_expr.etype ->
+		let return_pos = { e.epos with pmax = return_expr.epos.pmin - 1 } in
+		let exprs = [
+			fix_return_dynamic_from_void_function ctx return_is_void return_expr;
+			{ e with eexpr = TReturn None; epos = return_pos };
+		] in
+		{ e with
+			eexpr = TMeta (
+				(Meta.MergeBlock, [], null_pos),
+				mk (TBlock exprs) e.etype e.epos
+			);
+		}
+	| _ -> Type.map_expr (fix_return_dynamic_from_void_function ctx return_is_void) e
+
+let check_abstract_as_value e =
+	let rec loop e =
+		match e.eexpr with
+		| TField ({ eexpr = TTypeExpr _ }, _) -> ()
+		| TTypeExpr(TClassDecl {cl_kind = KAbstractImpl a}) when not (Meta.has Meta.RuntimeValue a.a_meta) ->
+			error "Cannot use abstract as value" e.epos
+		| _ -> Type.iter loop e
+	in
+	loop e;
+	e
+
 (* PASS 1 end *)
 
 (* Saves a class state so it can be restored later, e.g. after DCE or native path rewrite *)
 let save_class_state ctx t = match t with
 	| TClassDecl c ->
+		let vars = ref [] in
+		let rec save_vars e =
+			let add v = vars := (v, v.v_type) :: !vars in
+			match e.eexpr with
+				| TFunction fn ->
+					List.iter (fun (v, _) -> add v) fn.tf_args;
+					save_vars fn.tf_expr
+				| TVar (v, e) ->
+					add v;
+					Option.may save_vars e
+				| _ ->
+					iter save_vars e
+		in
 		let mk_field_restore f =
+			Option.may save_vars f.cf_expr;
 			let rec mk_overload_restore f =
 				f.cf_name,f.cf_kind,f.cf_expr,f.cf_type,f.cf_meta,f.cf_params
 			in
@@ -395,6 +424,7 @@ let save_class_state ctx t = match t with
 		let ofr = List.map (mk_field_restore) c.cl_ordered_fields in
 		let osr = List.map (mk_field_restore) c.cl_ordered_statics in
 		let init = c.cl_init in
+		Option.may save_vars init;
 		c.cl_restore <- (fun() ->
 			c.cl_super <- sup;
 			c.cl_implements <- impl;
@@ -409,6 +439,7 @@ let save_class_state ctx t = match t with
 			c.cl_constructor <- Option.map restore_field csr;
 			c.cl_overrides <- over;
 			c.cl_descendants <- [];
+			List.iter (fun (v, t) -> v.v_type <- t) !vars;
 		)
 	| _ ->
 		()
@@ -780,14 +811,28 @@ end
 let run com tctx main =
 	let detail_times = Common.raw_defined com "filter-times" in
 	let new_types = List.filter (fun t ->
-		(match t with
+		let cached = is_cached t in
+		begin match t with
 			| TClassDecl cls ->
 				List.iter (fun (iface,_) -> add_descendant iface cls) cls.cl_implements;
-				(match cls.cl_super with
+				begin match cls.cl_super with
 					| Some (csup,_) -> add_descendant csup cls
-					| None -> ())
-			| _ -> ());
-		not (is_cached t)
+					| None -> ()
+				end;
+				(* Save cf_expr_unoptimized early: We want to inline with the original expression
+				   on the next compilation. *)
+				if not cached then begin
+					let field cf = match cf.cf_expr with
+						| Some {eexpr = TFunction tf} -> cf.cf_expr_unoptimized <- Some tf
+						| _ -> ()
+					in
+					List.iter field cls.cl_ordered_fields;
+					List.iter field cls.cl_ordered_statics;
+					Option.may field cls.cl_constructor;
+				end;
+			| _ -> ()
+		end;
+		not cached
 	) com.types in
 	NullSafety.run com new_types;
 	(* PASS 1: general expression filters *)
@@ -795,7 +840,14 @@ let run com tctx main =
 		(* ForRemap.apply tctx; *)
 		VarLazifier.apply com;
 		AbstractCast.handle_abstract_casts tctx;
+	] in
+	let t = filter_timer detail_times ["expr 0"] in
+	List.iter (run_expression_filters tctx filters) new_types;
+	t();
+	let filters = [
+		fix_return_dynamic_from_void_function tctx true;
 		check_local_vars_init;
+		check_abstract_as_value;
 		if Common.defined com Define.OldConstructorInline then Optimizer.inline_constructors tctx else InlineConstructors.inline_constructors tctx;
 		Optimizer.reduce_expression tctx;
 		CapturedVars.captured_vars com;

+ 1 - 0
src/generators/genas3.ml

@@ -264,6 +264,7 @@ let rec type_str ctx t p =
 		| [], "Int" -> "int"
 		| [], "Float" -> "Number"
 		| [], "Bool" -> "Boolean"
+		| ["flash"], "AnyType" -> "*"
 		| _ -> s_path ctx true a.a_path p)
 	| TEnum (e,_) ->
 		if e.e_extern then "Object" else s_path ctx true e.e_path p

+ 122 - 73
src/generators/gencpp.ml

@@ -1728,43 +1728,48 @@ let cpp_is_dynamic_type = function
 ;;
 
 
-let rec cpp_type_of ctx haxe_type =
-   (match haxe_type with
-   | TMono r -> (match !r with None -> TCppDynamic | Some t -> cpp_type_of ctx t)
+let rec cpp_type_of stack ctx haxe_type =
+   if List.exists (fast_eq haxe_type) stack then
+      TCppDynamic
+   else begin
+      let stack = haxe_type :: stack in
+      (match haxe_type with
+      | TMono r -> (match !r with None -> TCppDynamic | Some t -> cpp_type_of stack ctx t)
 
-   | TEnum (enum,params) ->  TCppEnum(enum)
+      | TEnum (enum,params) ->  TCppEnum(enum)
 
-   | TInst ({ cl_path=([],"Array"); cl_kind = KTypeParameter _},_)
-      -> TCppObject
+      | TInst ({ cl_path=([],"Array"); cl_kind = KTypeParameter _},_)
+         -> TCppObject
 
-   | TInst ({ cl_kind = KTypeParameter _},_)
-      -> TCppDynamic
+      | TInst ({ cl_kind = KTypeParameter _},_)
+         -> TCppDynamic
 
-   | TInst (klass,params) ->
-      cpp_instance_type ctx klass params
+      | TInst (klass,params) ->
+         cpp_instance_type stack ctx klass params
 
-   | TAbstract (abs,pl) when not (Meta.has Meta.CoreType abs.a_meta) ->
-       cpp_type_from_path ctx abs.a_path pl (fun () ->
-            cpp_type_of ctx (Abstract.get_underlying_type abs pl) )
+      | TAbstract (abs,pl) when not (Meta.has Meta.CoreType abs.a_meta) ->
+         cpp_type_from_path stack ctx abs.a_path pl (fun () ->
+               cpp_type_of stack ctx (Abstract.get_underlying_type abs pl) )
 
-   | TAbstract (a,params) ->
-       cpp_type_from_path ctx a.a_path params (fun () ->
-            if is_scalar_abstract a then begin
-               let native =  get_meta_string a.a_meta Meta.Native in
-               TCppScalar(if native="" then join_class_path a.a_path "::" else native)
-            end else
-               TCppDynamic)
+      | TAbstract (a,params) ->
+         cpp_type_from_path stack ctx a.a_path params (fun () ->
+               if is_scalar_abstract a then begin
+                  let native =  get_meta_string a.a_meta Meta.Native in
+                  TCppScalar(if native="" then join_class_path a.a_path "::" else native)
+               end else
+                  TCppDynamic)
 
-   | TType (type_def,params) ->
-       cpp_type_from_path ctx type_def.t_path params (fun () ->
-          cpp_type_of ctx (apply_params type_def.t_params params type_def.t_type) )
+      | TType (type_def,params) ->
+         cpp_type_from_path stack ctx type_def.t_path params (fun () ->
+            cpp_type_of stack ctx (apply_params type_def.t_params params type_def.t_type) )
 
-   | TFun _ -> TCppObject
-   | TAnon _ -> TCppObject
-   | TDynamic _ -> TCppDynamic
-   | TLazy func -> cpp_type_of ctx (lazy_type func)
-   )
-   and  cpp_type_from_path ctx path params default =
+      | TFun _ -> TCppObject
+      | TAnon _ -> TCppObject
+      | TDynamic _ -> TCppDynamic
+      | TLazy func -> cpp_type_of stack ctx (lazy_type func)
+      )
+   end
+   and  cpp_type_from_path stack ctx path params default =
       match path,params with
       | ([],"Void"),_ -> TCppVoid
       | ([],"void"),_ -> TCppVoid (* for old code with @:void *)
@@ -1795,25 +1800,25 @@ let rec cpp_type_of ctx haxe_type =
 
       (* Things with type parameters hxcpp knows about ... *)
       | (["cpp"],"FastIterator"), [p] ->
-            TCppFastIterator(cpp_type_of ctx p)
+            TCppFastIterator(cpp_type_of stack ctx p)
       | (["cpp"],"Pointer"), [p] ->
-            TCppPointer("Pointer", cpp_type_of ctx p)
+            TCppPointer("Pointer", cpp_type_of stack ctx p)
       | (["cpp"],"ConstPointer"), [p] ->
-            TCppPointer("ConstPointer", cpp_type_of ctx p)
+            TCppPointer("ConstPointer", cpp_type_of stack ctx p)
       | (["cpp"],"RawPointer"), [p] ->
-            TCppRawPointer("", cpp_type_of ctx p)
+            TCppRawPointer("", cpp_type_of stack ctx p)
       | (["cpp"],"RawConstPointer"), [p] ->
-            TCppRawPointer("const ", cpp_type_of ctx p)
+            TCppRawPointer("const ", cpp_type_of stack ctx p)
       | (["cpp"],"Function"), [function_type; abi] ->
-            cpp_function_type_of ctx function_type abi;
+            cpp_function_type_of stack ctx function_type abi;
       | (["cpp"],"Callable"), [function_type]
       | (["cpp"],"CallableData"), [function_type] ->
-            cpp_function_type_of_string ctx function_type "";
+            cpp_function_type_of_string stack ctx function_type "";
       | (("cpp"::["objc"]),"ObjcBlock"), [function_type] ->
-            let args,ret = (cpp_function_type_of_args_ret ctx function_type) in
+            let args,ret = (cpp_function_type_of_args_ret stack ctx function_type) in
             TCppObjCBlock(args,ret)
       | (["haxe";"extern"], "Rest"),[rest] ->
-            TCppRest(cpp_type_of ctx rest)
+            TCppRest(cpp_type_of stack ctx rest)
       | (("cpp"::["objc"]),"Protocol"), [interface_type] ->
             (match follow interface_type with
             | TInst (klass,[]) when klass.cl_interface ->
@@ -1823,16 +1828,16 @@ let rec cpp_type_of ctx haxe_type =
                    assert false;
             )
       | (["cpp"],"Reference"), [param] ->
-            TCppReference(cpp_type_of ctx param)
+            TCppReference(cpp_type_of stack ctx param)
       | (["cpp"],"Struct"), [param] ->
-            TCppStruct(cpp_type_of ctx param)
+            TCppStruct(cpp_type_of stack ctx param)
       | (["cpp"],"Star"), [param] ->
-            TCppStar(cpp_type_of_pointer ctx param,false)
+            TCppStar(cpp_type_of_pointer stack ctx param,false)
       | (["cpp"],"ConstStar"), [param] ->
-            TCppStar(cpp_type_of_pointer ctx param,true)
+            TCppStar(cpp_type_of_pointer stack ctx param,true)
 
       | ([],"Array"), [p] ->
-         let arrayOf = cpp_type_of ctx p in
+         let arrayOf = cpp_type_of stack ctx p in
          (match arrayOf with
             | TCppVoid (* ? *)
             | TCppDynamic ->
@@ -1857,55 +1862,55 @@ let rec cpp_type_of ctx haxe_type =
          )
 
       | ([],"Null"), [p] ->
-            cpp_type_of_null ctx p
+            cpp_type_of_null stack ctx p
 
       | _ -> default ()
 
-   and cpp_type_of_null ctx p =
-     let baseType = cpp_type_of ctx p in
+   and cpp_type_of_null stack ctx p =
+     let baseType = cpp_type_of stack ctx p in
      if (type_has_meta_key p Meta.NotNull) || (is_cpp_scalar baseType) then
         TCppObject
      else
         baseType
-   and cpp_type_of_pointer ctx p =
+   and cpp_type_of_pointer stack ctx p =
      match p with
-     | TAbstract ({ a_path = ([],"Null") },[t]) -> cpp_type_of ctx t
-     | x ->  cpp_type_of ctx x
+     | TAbstract ({ a_path = ([],"Null") },[t]) -> cpp_type_of stack ctx t
+     | x ->  cpp_type_of stack ctx x
    (* Optional types are Dynamic if they norally could not be null *)
-   and cpp_fun_arg_type_of ctx tvar opt =
+   and cpp_fun_arg_type_of stack ctx tvar opt =
       match opt with
-      | Some _ -> cpp_type_of_null ctx tvar.t_type
-      | _ -> cpp_type_of ctx tvar.t_type
+      | Some _ -> cpp_type_of_null stack ctx tvar.t_type
+      | _ -> cpp_type_of stack ctx tvar.t_type
 
-   and cpp_tfun_arg_type_of ctx opt t =
-      if opt then cpp_type_of_null ctx t else cpp_type_of ctx t
+   and cpp_tfun_arg_type_of stack ctx opt t =
+      if opt then cpp_type_of_null stack ctx t else cpp_type_of stack ctx t
 
-   and cpp_function_type_of ctx function_type abi =
+   and cpp_function_type_of stack ctx function_type abi =
       let abi = (match follow abi with
                  | TInst (klass1,_) -> get_meta_string klass1.cl_meta Meta.Abi
                  | _ -> assert false )
       in
-      cpp_function_type_of_string ctx function_type abi
-   and cpp_function_type_of_string ctx function_type abi_string =
-      let args,ret = cpp_function_type_of_args_ret ctx function_type in
+      cpp_function_type_of_string stack ctx function_type abi
+   and cpp_function_type_of_string stack ctx function_type abi_string =
+      let args,ret = cpp_function_type_of_args_ret stack ctx function_type in
       TCppFunction(args, ret, abi_string)
 
-   and cpp_function_type_of_args_ret ctx function_type =
+   and cpp_function_type_of_args_ret stack ctx function_type =
       match follow function_type with
       | TFun(args,ret) ->
           (* Optional types are Dynamic if they norally could not be null *)
           let  cpp_arg_type_of = fun(_,optional,haxe_type) ->
              if optional then
-                cpp_type_of_null ctx haxe_type
+                cpp_type_of_null stack ctx haxe_type
              else
-                cpp_type_of ctx haxe_type
+                cpp_type_of stack ctx haxe_type
           in
-          List.map cpp_arg_type_of args, cpp_type_of ctx ret
+          List.map cpp_arg_type_of args, cpp_type_of stack ctx ret
       | _ ->  (* ? *)
           [TCppVoid], TCppVoid
 
-   and cpp_instance_type ctx klass params =
-      cpp_type_from_path ctx klass.cl_path params (fun () ->
+   and cpp_instance_type stack ctx klass params =
+      cpp_type_from_path stack ctx klass.cl_path params (fun () ->
          if is_objc_class klass then
             TCppObjC(klass)
          else if klass.cl_interface && is_native_gen_class klass then
@@ -1917,6 +1922,17 @@ let rec cpp_type_of ctx haxe_type =
          else
             TCppInst(klass)
        )
+
+let cpp_type_of ctx = cpp_type_of [] ctx
+and cpp_type_from_path ctx = cpp_type_from_path [] ctx
+and cpp_type_of_null ctx = cpp_type_of_null [] ctx
+and cpp_type_of_pointer ctx = cpp_type_of_pointer [] ctx
+and cpp_fun_arg_type_of ctx = cpp_fun_arg_type_of [] ctx
+and cpp_tfun_arg_type_of ctx = cpp_tfun_arg_type_of [] ctx
+and cpp_function_type_of ctx = cpp_function_type_of [] ctx
+and cpp_function_type_of_string ctx = cpp_function_type_of_string [] ctx
+and cpp_function_type_of_args_ret ctx = cpp_function_type_of_args_ret [] ctx
+and cpp_instance_type ctx = cpp_instance_type [] ctx
 ;;
 
 
@@ -4267,8 +4283,39 @@ let is_override class_def field =
    List.exists (fun f -> f.cf_name = field) class_def.cl_overrides
 ;;
 
+(*
+   Functions are added in reverse order (oldest on right), then list is reversed because this is easier in ocaml
+   The order is important because cppia looks up functions by index
+*)
+
+
+let current_virtual_functions_rev clazz base_functions =
+   List.fold_left (fun result elem -> match follow elem.cf_type, elem.cf_kind  with
+      | _, Method MethDynamic -> result
+      | TFun (args,return_type), Method _  ->
+          if (is_override clazz elem.cf_name ) then
+             List.map (fun (e,a,r) ->  if e.cf_name<>elem.cf_name then (e,a,r) else  (elem,args,return_type) ) result
+          else
+             (elem,args,return_type) :: result
+      | _,_ -> result
+    ) base_functions clazz.cl_ordered_fields
+;;
+
+let all_virtual_functions clazz =
+  let rec all_virtual_functions_rec clazz =
+   current_virtual_functions_rev clazz (match clazz.cl_super with
+       | Some def -> all_virtual_functions_rec (fst def)
+       | _ -> []
+     )
+   in
+   List.rev (all_virtual_functions_rec clazz)
+;;
+
+
+
+(*
 let current_virtual_functions clazz parents override_types =
-  List.rev (List.fold_left (fun result elem -> match follow elem.cf_type, elem.cf_kind  with
+  List.fold_left (fun result elem -> match follow elem.cf_type, elem.cf_kind  with
     | _, Method MethDynamic -> result
     | TFun (args,return_type), Method _ ->
         if override_types then
@@ -4277,17 +4324,18 @@ let current_virtual_functions clazz parents override_types =
            result
         else
            (elem,args,return_type) :: result
-    | _,_ -> result ) parents clazz.cl_ordered_fields)
+    | _,_ -> result ) parents (List.rev clazz.cl_ordered_fields)
 ;;
 
 let all_virtual_functions clazz override_types =
    let rec all_virtual_functions clazz =
       current_virtual_functions clazz (match clazz.cl_super with
          | Some def -> all_virtual_functions (fst def)
-         | _ -> [] ) override_types
+         | _ -> [] ) false
    in
    all_virtual_functions clazz
 ;;
+*)
 
 
 let rec unreflective_type t =
@@ -4778,7 +4826,7 @@ let find_referenced_types_flags ctx obj field_name super_deps constructor_deps h
             List.filter (fun f -> f.cf_name=field_name) fields_and_constructor in
       List.iter visit_field fields_and_constructor;
       if (include_super_args) then
-         List.iter visit_field (List.map (fun (a,_,_) -> a ) (all_virtual_functions class_def false));
+         List.iter visit_field (List.map (fun (a,_,_) -> a ) (all_virtual_functions class_def ));
 
       (* Add super & interfaces *)
       if is_native_gen_class class_def then
@@ -5626,7 +5674,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta
    in
 
    let not_toString = fun (field,args,_) -> field.cf_name<>"toString" || class_def.cl_interface in
-   let functions = List.filter not_toString (all_virtual_functions class_def true) in
+   let functions = List.filter not_toString (all_virtual_functions class_def) in
 
    (* Constructor definition *)
    let cargs = (constructor_arg_var_list class_def baseCtx) in
@@ -5642,14 +5690,15 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta
 
    let outputConstructor ctx out isHeader =
       let classScope = if isHeader then "" else class_name ^ "::" in
-      out (ptr_name ^ " " ^ classScope ^ "__new(" ^constructor_type_args ^") {\n");
+      let staticHead = if isHeader then "inline static " else "" in
+      out (staticHead ^ ptr_name ^ " " ^ classScope ^ "__new(" ^constructor_type_args ^") {\n");
       out ("\t" ^ ptr_name ^ " __this = new " ^ class_name ^ "();\n");
          out ("\t__this->__construct(" ^ constructor_args ^ ");\n");
       out ("\treturn __this;\n");
       out ("}\n\n");
 
       if can_quick_alloc then begin
-         out ((if isHeader then "static " else "") ^ ptr_name ^ " " ^ classScope ^ "__alloc(hx::Ctx *_hx_ctx" ^
+         out (staticHead ^ ptr_name ^ " " ^ classScope ^ "__alloc(hx::Ctx *_hx_ctx" ^
             (if constructor_type_args="" then "" else "," ^constructor_type_args)  ^") {\n");
          out ("\t" ^ class_name ^ " *__this = (" ^ class_name ^ "*)(hx::Ctx::alloc(_hx_ctx, sizeof(" ^ class_name ^ "), " ^ isContainer ^", " ^ gcName ^ "));\n");
          out ("\t*(void **)__this = " ^ class_name ^ "::_hx_vtable;\n");
@@ -6261,9 +6310,9 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta
       in
 
       let new_sctipt_functions = if newInteface then
-            all_virtual_functions class_def false
+            all_virtual_functions class_def
          else
-            current_virtual_functions class_def [] false
+            List.rev (current_virtual_functions_rev class_def [])
       in
       let sctipt_name = class_name ^ "__scriptable" in
 

+ 68 - 59
src/generators/gencs.ml

@@ -918,60 +918,65 @@ let generate con =
 		) tl
 		in
 
-		let rec real_type t =
+		let rec real_type stack t =
 			let t = gen.gfollow#run_f t in
-			let ret = match t with
-				| TAbstract({ a_path = ([], "Null") }, [t]) ->
-					(*
-						Null<> handling is a little tricky.
-						It will only change to haxe.lang.Null<> when the actual type is non-nullable or a type parameter
-						It works on cases such as Hash<T> returning Null<T> since cast_detect will invoke real_type at the original type,
-						Null<T>, which will then return the type haxe.lang.Null<>
-					*)
-					if erase_generics then
-						if is_cs_basic_type t then
-							t_dynamic
+			if List.exists (fast_eq t) stack then
+				t_dynamic
+			else begin
+				let stack = t :: stack in
+				let ret = match t with
+					| TAbstract({ a_path = ([], "Null") }, [t]) ->
+						(*
+							Null<> handling is a little tricky.
+							It will only change to haxe.lang.Null<> when the actual type is non-nullable or a type parameter
+							It works on cases such as Hash<T> returning Null<T> since cast_detect will invoke real_type at the original type,
+							Null<T>, which will then return the type haxe.lang.Null<>
+						*)
+						if erase_generics then
+							if is_cs_basic_type t then
+								t_dynamic
+							else
+								real_type stack t
 						else
-							real_type t
-					else
-						(match real_type t with
-							| TInst( { cl_kind = KTypeParameter _ }, _ ) -> TInst(null_t, [t])
-							| t when is_cs_basic_type t -> TInst(null_t, [t])
-							| _ -> real_type t)
-				| TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) ->
-					real_type (Abstract.get_underlying_type a pl)
-				| TAbstract ({ a_path = (["cs";"_Flags"], "EnumUnderlying") }, [t]) ->
-					real_type t
-				| TInst( { cl_path = (["cs";"system"], "String") }, [] ) ->
-					gen.gcon.basic.tstring;
-				| TInst( { cl_path = (["haxe"], "Int32") }, [] ) -> gen.gcon.basic.tint
-				| TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> ti64
-				| TAbstract( { a_path = [],"Class" }, _ )
-				| TAbstract( { a_path = [],"Enum" }, _ )
-				| TAbstract( { a_path = ["haxe";"extern"],"Rest" }, _ )
-				| TInst( { cl_path = ([], "Class") }, _ )
-				| TInst( { cl_path = ([], "Enum") }, _ ) -> TInst(ttype,[])
-				| TInst( ({ cl_kind = KTypeParameter _ } as cl), _ ) when erase_generics && not (Meta.has Meta.NativeGeneric cl.cl_meta) ->
-					t_dynamic
-				| TInst({ cl_kind = KExpr _ }, _) -> t_dynamic
-				| TEnum(_, [])
-				| TInst(_, []) -> t
-				| TInst(cl, params) when
-					has_tdyn params &&
-					Hashtbl.mem ifaces cl.cl_path ->
-						TInst(Hashtbl.find ifaces cl.cl_path, [])
-				| TEnum(e, params) ->
-					TEnum(e, List.map (fun _ -> t_dynamic) params)
-				| TInst(cl, params) when Meta.has Meta.Enum cl.cl_meta ->
-					TInst(cl, List.map (fun _ -> t_dynamic) params)
-				| TInst(cl, params) -> TInst(cl, change_param_type (TClassDecl cl) params)
-				| TAbstract _
-				| TType _ -> t
-				| TAnon (anon) when (match !(anon.a_status) with | Statics _ | EnumStatics _ | AbstractStatics _ -> true | _ -> false) -> t
-				| TFun _ -> TInst(fn_cl,[])
-				| _ -> t_dynamic
-			in
-			ret
+							(match real_type stack t with
+								| TInst( { cl_kind = KTypeParameter _ }, _ ) -> TInst(null_t, [t])
+								| t when is_cs_basic_type t -> TInst(null_t, [t])
+								| _ -> real_type stack t)
+					| TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) ->
+						real_type stack (Abstract.get_underlying_type a pl)
+					| TAbstract ({ a_path = (["cs";"_Flags"], "EnumUnderlying") }, [t]) ->
+						real_type stack t
+					| TInst( { cl_path = (["cs";"system"], "String") }, [] ) ->
+						gen.gcon.basic.tstring;
+					| TInst( { cl_path = (["haxe"], "Int32") }, [] ) -> gen.gcon.basic.tint
+					| TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> ti64
+					| TAbstract( { a_path = [],"Class" }, _ )
+					| TAbstract( { a_path = [],"Enum" }, _ )
+					| TAbstract( { a_path = ["haxe";"extern"],"Rest" }, _ )
+					| TInst( { cl_path = ([], "Class") }, _ )
+					| TInst( { cl_path = ([], "Enum") }, _ ) -> TInst(ttype,[])
+					| TInst( ({ cl_kind = KTypeParameter _ } as cl), _ ) when erase_generics && not (Meta.has Meta.NativeGeneric cl.cl_meta) ->
+						t_dynamic
+					| TInst({ cl_kind = KExpr _ }, _) -> t_dynamic
+					| TEnum(_, [])
+					| TInst(_, []) -> t
+					| TInst(cl, params) when
+						has_tdyn params &&
+						Hashtbl.mem ifaces cl.cl_path ->
+							TInst(Hashtbl.find ifaces cl.cl_path, [])
+					| TEnum(e, params) ->
+						TEnum(e, List.map (fun _ -> t_dynamic) params)
+					| TInst(cl, params) when Meta.has Meta.Enum cl.cl_meta ->
+						TInst(cl, List.map (fun _ -> t_dynamic) params)
+					| TInst(cl, params) -> TInst(cl, change_param_type stack (TClassDecl cl) params)
+					| TAbstract _
+					| TType _ -> t
+					| TAnon (anon) when (match !(anon.a_status) with | Statics _ | EnumStatics _ | AbstractStatics _ -> true | _ -> false) -> t
+					| TFun _ -> TInst(fn_cl,[])
+					| _ -> t_dynamic
+				in
+				ret
+			end
 		and
 
 		(*
@@ -982,7 +987,7 @@ let generate con =
 			To avoid confusion between Generic<Dynamic> (which has a different meaning in hxcs AST),
 			all those references are using dynamic_anon, which means Generic<{}>
 		*)
-		change_param_type md tl =
+		change_param_type stack md tl =
 			let types = match md with
 				| TClassDecl c -> c.cl_params
 				| TEnumDecl e -> []
@@ -991,7 +996,7 @@ let generate con =
 			in
 			let is_hxgeneric = if types = [] then is_hxgen md else (RealTypeParams.is_hxgeneric md) in
 			let ret t =
-				let t_changed = real_type t in
+				let t_changed = real_type stack t in
 				match is_hxgeneric, t_changed with
 				| false, _ -> t
 				(*
@@ -1014,6 +1019,9 @@ let generate con =
 				List.map ret tl
 		in
 
+		let real_type = real_type []
+		and change_param_type = change_param_type [] in
+
 		let is_dynamic t = match real_type t with
 			| TMono _ | TDynamic _
 			| TInst({ cl_kind = KTypeParameter _ }, _) -> true
@@ -3339,15 +3347,16 @@ let generate con =
 		let hashes = Hashtbl.fold (fun i s acc -> incr nhash; (normalize_i i,s) :: acc) rcf_ctx.rcf_hash_fields [] in
 		let hashes = List.sort (fun (i,s) (i2,s2) -> compare i i2) hashes in
 
-		let haxe_libs = List.filter (function (_,_,_,lookup) -> is_some (lookup (["haxe";"lang"], "DceNo"))) gen.gcon.net_libs in
+		let haxe_libs = List.filter (function net_lib -> is_some (net_lib#lookup (["haxe";"lang"], "DceNo"))) gen.gcon.native_libs.net_libs in
 		(try
 			(* first let's see if we're adding a -net-lib that has already a haxe.lang.FieldLookup *)
-			let name,_,_,_ = List.find (function (_,_,_,lookup) -> is_some (lookup (["haxe";"lang"], "FieldLookup"))) gen.gcon.net_libs in
+			let net_lib = List.find (function net_lib -> is_some (net_lib#lookup (["haxe";"lang"], "FieldLookup"))) gen.gcon.native_libs.net_libs in
+			let name = net_lib#get_name in
 			if not (Common.defined gen.gcon Define.DllImport) then begin
 				gen.gcon.warning ("The -net-lib with path " ^ name ^ " contains a Haxe-generated assembly. Please define `-D dll_import` to handle Haxe-generated dll import correctly") null_pos;
 				raise Not_found
 			end;
-			if not (List.exists (function (n,_,_,_) -> n = name) haxe_libs) then
+			if not (List.exists (function net_lib -> net_lib#get_name = name) haxe_libs) then
 				gen.gcon.warning ("The -net-lib with path " ^ name ^ " contains a Haxe-generated assembly, however it wasn't compiled with `-dce no`. Recompilation with `-dce no` is recommended") null_pos;
 			(* it has; in this case, we need to add the used fields on each __init__ *)
 			flookup_cl.cl_extern <- true;
@@ -3399,8 +3408,8 @@ let generate con =
 						| (p,_) -> p
 					in
 					let path = (pack, snd c.cl_path ^ extra) in
-					ignore (List.find (function (_,_,_,lookup) ->
-						is_some (lookup path)) haxe_libs);
+					ignore (List.find (function net_lib ->
+						is_some (net_lib#lookup path)) haxe_libs);
 					c.cl_extern <- true;
 				with | Not_found -> ())
 				| _ -> ()) gen.gtypes

+ 20 - 12
src/generators/genhl.ml

@@ -352,6 +352,18 @@ let fake_tnull =
 		a_params = ["T",t_dynamic];
 	}
 
+let get_rec_cache ctx t none_callback not_found_callback =
+	try
+		match !(List.assq t ctx.rec_cache) with
+		| None -> none_callback()
+		| Some t -> t
+	with Not_found ->
+		let tref = ref None in
+		ctx.rec_cache <- (t,tref) :: ctx.rec_cache;
+		let t = not_found_callback tref in
+		ctx.rec_cache <- List.tl ctx.rec_cache;
+		t
+
 let rec to_type ?tref ctx t =
 	match t with
 	| TMono r ->
@@ -359,17 +371,11 @@ let rec to_type ?tref ctx t =
 		| None -> HDyn
 		| Some t -> to_type ?tref ctx t)
 	| TType (td,tl) ->
-		let t = (try
-			match !(List.assq t ctx.rec_cache) with
-			| None -> abort "Unsupported recursive type" td.t_pos
-			| Some t -> t
-		with Not_found ->
-			let tref = ref None in
-			ctx.rec_cache <- (t,tref) :: ctx.rec_cache;
-			let t = to_type ~tref ctx (apply_params td.t_params tl td.t_type) in
-			ctx.rec_cache <- List.tl ctx.rec_cache;
-			t
-		) in
+		let t =
+			get_rec_cache ctx t
+				(fun() -> abort "Unsupported recursive type" td.t_pos)
+				(fun tref -> to_type ~tref ctx (apply_params td.t_params tl td.t_type))
+		in
 		(match td.t_path with
 		| ["haxe";"macro"], name -> Hashtbl.replace ctx.macro_typedefs name t; t
 		| _ -> t)
@@ -454,7 +460,9 @@ let rec to_type ?tref ctx t =
 			| ["haxe";"macro"], "Position" -> HAbstract ("macro_pos", alloc_string ctx "macro_pos")
 			| _ -> failwith ("Unknown core type " ^ s_type_path a.a_path))
 		else
-			to_type ?tref ctx (Abstract.get_underlying_type a pl)
+			get_rec_cache ctx t
+				(fun() -> HDyn)
+				(fun tref -> to_type ~tref ctx (Abstract.get_underlying_type a pl))
 
 and resolve_class ctx c pl statics =
 	let not_supported() =

+ 79 - 71
src/generators/genjava.ml

@@ -962,12 +962,12 @@ let rec get_fun_modifiers meta access modifiers =
 
 let generate con =
 	let exists = ref false in
-	con.java_libs <- List.map (fun (file,std,close,la,gr) ->
-		if String.ends_with file "hxjava-std.jar" then begin
+	List.iter (fun java_lib ->
+		if String.ends_with java_lib#get_file_path "hxjava-std.jar" then begin
 			exists := true;
-			(file,true,close,la,gr)
-		end else
-			(file,std,close,la,gr)) con.java_libs;
+			java_lib#add_flag NativeLibraries.FlagIsStd;
+		end;
+	) con.native_libs.java_libs;
 	if not !exists then
 		failwith "Your version of hxjava is outdated. Please update it by running: `haxelib update hxjava`";
 	let gen = new_ctx con in
@@ -1215,68 +1215,72 @@ let generate con =
 		| _ -> false
 	in
 
-	let rec t_s pos t =
-		match real_type t with
-			(* basic types *)
-			| TAbstract ({ a_path = ([], "Bool") },[]) -> "boolean"
-			| TAbstract ({ a_path = ([], "Void") },[]) ->
-					path_s_import pos (["java";"lang"], "Object") []
-			| TAbstract ({ a_path = ([],"Float") },[]) -> "double"
-			| TAbstract ({ a_path = ([],"Int") },[]) -> "int"
-			| TType ({ t_path = ["java"], "Int64" },[])
-			| TAbstract ({ a_path = ["java"], "Int64" },[]) -> "long"
-			| TType ({ t_path = ["java"],"Int8" },[])
-			| TAbstract ({ a_path = ["java"],"Int8" },[]) -> "byte"
-			| TType ({ t_path = ["java"],"Int16" },[])
-			| TAbstract ({ a_path = ["java"],"Int16" },[]) -> "short"
-			| TType ({ t_path = ["java"],"Char16" },[])
-			| TAbstract ({ a_path = ["java"],"Char16" },[]) -> "char"
-			| TType ({ t_path = [],"Single" },[])
-			| TAbstract ({ a_path = [],"Single" },[]) -> "float"
-			| TInst ({ cl_path = ["haxe"],"Int32" },[])
-			| TAbstract ({ a_path = ["haxe"],"Int32" },[]) -> "int"
-			| TInst ({ cl_path = ["haxe"],"Int64" },[])
-			| TAbstract ({ a_path = ["haxe"],"Int64" },[]) -> "long"
-			| TInst({ cl_path = (["java"], "NativeArray") }, [param]) ->
-				let rec check_t_s t =
-					match real_type t with
-						| TInst({ cl_path = (["java"], "NativeArray") }, [param]) ->
-							(check_t_s param) ^ "[]"
-						| _ -> t_s pos (run_follow gen t)
-				in
-				(check_t_s param) ^ "[]"
-
-			(* end of basic types *)
-			| TInst ({ cl_kind = KTypeParameter _; cl_path=p }, []) -> snd p
-			| TAbstract ({ a_path = [], "Dynamic" },[]) ->
-					path_s_import pos (["java";"lang"], "Object") []
-			| TMono r -> (match !r with | None -> "java.lang.Object" | Some t -> t_s pos (run_follow gen t))
-			| TInst ({ cl_path = [], "String" }, []) ->
-					path_s_import pos (["java";"lang"], "String") []
-			| TAbstract ({ a_path = [], "Class" }, [p]) | TAbstract ({ a_path = [], "Enum" }, [p])
-			| TInst ({ cl_path = [], "Class" }, [p]) | TInst ({ cl_path = [], "Enum" }, [p]) ->
-					path_param_s pos (TClassDecl cl_cl) (["java";"lang"], "Class") [p] []
-			| TAbstract ({ a_path = [], "Class" }, _) | TAbstract ({ a_path = [], "Enum" }, _)
-			| TInst ({ cl_path = [], "Class" }, _) | TInst ({ cl_path = [], "Enum" }, _) ->
-					path_s_import pos (["java";"lang"], "Class") []
-			| TEnum ({e_path = p; e_meta = meta}, _) ->
-					path_s_import pos p meta
-			| TInst (({cl_path = p; cl_meta = meta} as cl), _) when Meta.has Meta.Enum cl.cl_meta ->
-					path_s_import pos p meta
-			| TInst (({cl_path = p; cl_meta = meta} as cl), params) -> (path_param_s pos (TClassDecl cl) p params meta)
-			| TType (({t_path = p; t_meta = meta} as t), params) -> (path_param_s pos (TTypeDecl t) p params meta)
-			| TAnon (anon) ->
-				(match !(anon.a_status) with
-					| Statics _ | EnumStatics _ | AbstractStatics _ ->
-							path_s_import pos (["java";"lang"], "Class") []
-					| _ ->
-							path_s_import pos (["java";"lang"], "Object") [])
-				| TDynamic _ ->
+	let rec t_s stack pos t =
+		if List.exists (fast_eq t) stack then
+			path_s_import pos (["java";"lang"], "Object") []
+		else begin
+			let stack = t :: stack in
+			match real_type t with
+				(* basic types *)
+				| TAbstract ({ a_path = ([], "Bool") },[]) -> "boolean"
+				| TAbstract ({ a_path = ([], "Void") },[]) ->
 						path_s_import pos (["java";"lang"], "Object") []
-			(* No Lazy type nor Function type made. That's because function types will be at this point be converted into other types *)
-			| _ -> if !strict_mode then begin trace ("[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"); assert false end else "[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"
+				| TAbstract ({ a_path = ([],"Float") },[]) -> "double"
+				| TAbstract ({ a_path = ([],"Int") },[]) -> "int"
+				| TType ({ t_path = ["java"], "Int64" },[])
+				| TAbstract ({ a_path = ["java"], "Int64" },[]) -> "long"
+				| TType ({ t_path = ["java"],"Int8" },[])
+				| TAbstract ({ a_path = ["java"],"Int8" },[]) -> "byte"
+				| TType ({ t_path = ["java"],"Int16" },[])
+				| TAbstract ({ a_path = ["java"],"Int16" },[]) -> "short"
+				| TType ({ t_path = ["java"],"Char16" },[])
+				| TAbstract ({ a_path = ["java"],"Char16" },[]) -> "char"
+				| TType ({ t_path = [],"Single" },[])
+				| TAbstract ({ a_path = [],"Single" },[]) -> "float"
+				| TInst ({ cl_path = ["haxe"],"Int32" },[])
+				| TAbstract ({ a_path = ["haxe"],"Int32" },[]) -> "int"
+				| TInst ({ cl_path = ["haxe"],"Int64" },[])
+				| TAbstract ({ a_path = ["haxe"],"Int64" },[]) -> "long"
+				| TInst({ cl_path = (["java"], "NativeArray") }, [param]) ->
+					let rec check_t_s t =
+						match real_type t with
+							| TInst({ cl_path = (["java"], "NativeArray") }, [param]) ->
+								(check_t_s param) ^ "[]"
+							| _ -> t_s stack pos (run_follow gen t)
+					in
+					(check_t_s param) ^ "[]"
 
-	and param_t_s pos t =
+				(* end of basic types *)
+				| TInst ({ cl_kind = KTypeParameter _; cl_path=p }, []) -> snd p
+				| TAbstract ({ a_path = [], "Dynamic" },[]) ->
+						path_s_import pos (["java";"lang"], "Object") []
+				| TMono r -> (match !r with | None -> "java.lang.Object" | Some t -> t_s stack pos (run_follow gen t))
+				| TInst ({ cl_path = [], "String" }, []) ->
+						path_s_import pos (["java";"lang"], "String") []
+				| TAbstract ({ a_path = [], "Class" }, [p]) | TAbstract ({ a_path = [], "Enum" }, [p])
+				| TInst ({ cl_path = [], "Class" }, [p]) | TInst ({ cl_path = [], "Enum" }, [p]) ->
+						path_param_s stack pos (TClassDecl cl_cl) (["java";"lang"], "Class") [p] []
+				| TAbstract ({ a_path = [], "Class" }, _) | TAbstract ({ a_path = [], "Enum" }, _)
+				| TInst ({ cl_path = [], "Class" }, _) | TInst ({ cl_path = [], "Enum" }, _) ->
+						path_s_import pos (["java";"lang"], "Class") []
+				| TEnum ({e_path = p; e_meta = meta}, _) ->
+						path_s_import pos p meta
+				| TInst (({cl_path = p; cl_meta = meta} as cl), _) when Meta.has Meta.Enum cl.cl_meta ->
+						path_s_import pos p meta
+				| TInst (({cl_path = p; cl_meta = meta} as cl), params) -> (path_param_s stack pos (TClassDecl cl) p params meta)
+				| TType (({t_path = p; t_meta = meta} as t), params) -> (path_param_s stack pos (TTypeDecl t) p params meta)
+				| TAnon (anon) ->
+					(match !(anon.a_status) with
+						| Statics _ | EnumStatics _ | AbstractStatics _ ->
+								path_s_import pos (["java";"lang"], "Class") []
+						| _ ->
+								path_s_import pos (["java";"lang"], "Object") [])
+					| TDynamic _ ->
+							path_s_import pos (["java";"lang"], "Object") []
+				(* No Lazy type nor Function type made. That's because function types will be at this point be converted into other types *)
+				| _ -> if !strict_mode then begin trace ("[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"); assert false end else "[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"
+		end
+	and param_t_s stack pos t =
 		match run_follow gen t with
 			| TAbstract ({ a_path = ([], "Bool") },[]) ->
 					path_s_import pos (["java";"lang"], "Boolean") []
@@ -1306,18 +1310,22 @@ let generate con =
 			| TAbstract ({ a_path = [],"Single" },[]) ->
 					path_s_import pos (["java";"lang"], "Float") []
 			| TDynamic _ -> "?"
-			| TInst (cl, params) -> t_s pos (TInst(cl, change_param_type (TClassDecl cl) params))
-			| TType (cl, params) -> t_s pos (TType(cl, change_param_type (TTypeDecl cl) params))
-			| TEnum (e, params) -> t_s pos (TEnum(e, change_param_type (TEnumDecl e) params))
-			| _ -> t_s pos t
+			| TInst (cl, params) -> t_s stack pos (TInst(cl, change_param_type (TClassDecl cl) params))
+			| TType (cl, params) -> t_s stack pos (TType(cl, change_param_type (TTypeDecl cl) params))
+			| TEnum (e, params) -> t_s stack pos (TEnum(e, change_param_type (TEnumDecl e) params))
+			| _ -> t_s stack pos t
 
-	and path_param_s pos md path params meta =
+	and path_param_s stack pos md path params meta =
 			match params with
 				| [] -> path_s_import pos path meta
 				| _ when has_tdynamic (change_param_type md params) -> path_s_import pos path meta
-				| _ -> sprintf "%s<%s>" (path_s_import pos path meta) (String.concat ", " (List.map (fun t -> param_t_s pos t) (change_param_type md params)))
+				| _ -> sprintf "%s<%s>" (path_s_import pos path meta) (String.concat ", " (List.map (fun t -> param_t_s stack pos t) (change_param_type md params)))
 	in
 
+	let t_s = t_s []
+	and param_t_s = param_t_s []
+	and path_param_s = path_param_s [] in
+
 	let rett_s pos t =
 		match t with
 			| TAbstract ({ a_path = ([], "Void") },[]) -> "void"

+ 105 - 47
src/generators/genjvm.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open Globals
 open Ast
 open Common
@@ -12,6 +31,9 @@ open JvmSignature
 open JvmMethod
 open JvmBuilder
 
+(* Note: This module is the bridge between Haxe structures and JVM structures. No module in generators/jvm should reference any
+   Haxe-specific type. *)
+
 (* hacks *)
 
 let rec pow a b = match b with
@@ -119,7 +141,7 @@ type field_generation_info = {
 	mutable has_this_before_super : bool;
 	(* This is an ordered list of fields that are targets of super() calls which is determined during
 	   pre-processing. The generator can pop from this list assuming that it processes the expression
-	   in the same order (which is should). *)
+	   in the same order (which it should). *)
 	mutable super_call_fields : (tclass * tclass_field) list;
 }
 
@@ -207,10 +229,10 @@ let rec jsignature_of_type stack t =
 		| Some t -> jsignature_of_type t
 		| None -> object_sig
 		end
-	| TInst({cl_path = ([],"String")},[]) -> string_sig
-	| TInst({cl_path = ([],"Array")},[t]) ->
+	| TInst({cl_path = (["haxe";"root"],"String")},[]) -> string_sig
+	| TInst({cl_path = (["haxe";"root"],"Array")},[t]) ->
 		let t = get_boxed_type (jsignature_of_type t) in
-		TObject(([],"Array"),[TType(WNone,t)])
+		TObject((["haxe";"root"],"Array"),[TType(WNone,t)])
 	| TInst({cl_path = (["java"],"NativeArray")},[t]) ->
 		TArray(jsignature_of_type t,None)
 	| TInst({cl_kind = KTypeParameter [t]},_) -> jsignature_of_type t
@@ -687,7 +709,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 			| _ ->
 				default();
 			end
-		| FDynamic s | FInstance(_,_,{cf_name = s}) | FEnum(_,{ef_name = s}) | FClosure(Some({cl_interface = true},_),{cf_name = s}) ->
+		| FDynamic s | FInstance(_,_,{cf_name = s}) | FEnum(_,{ef_name = s}) | FClosure(Some({cl_interface = true},_),{cf_name = s}) | FClosure(None,{cf_name = s}) ->
 			self#texpr rvalue_any e1;
 			jm#string s;
 			jm#invokestatic haxe_jvm_path "readField" (method_sig [object_sig;string_sig] (Some object_sig));
@@ -697,8 +719,6 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 			jm#read_closure false c.cl_path cf.cf_name jsig;
 			self#texpr rvalue_any e1;
 			jm#invokevirtual method_handle_path "bindTo" (method_sig [object_sig] (Some method_handle_sig));
-		| _ ->
-			assert false
 
 	method read_write ret ak e (f : unit -> unit) =
 		let apply dup =
@@ -741,7 +761,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 			jm#invokestatic haxe_jvm_path "writeField" (method_sig [object_sig;string_sig;object_sig] None)
 		| TArray(e1,e2) ->
 			begin match follow e1.etype with
-				| TInst({cl_path = ([],"Array")} as c,[t]) ->
+				| TInst({cl_path = (["haxe";"root"],"Array")} as c,[t]) ->
 					let t = self#mknull t in
 					self#texpr rvalue_any e1;
 					if ak <> AKNone then code#dup;
@@ -1030,14 +1050,30 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 						jm#get_code#bconst (op = CmpNe)
 					)
 					(fun () ->
-						jm#cast ~not_null:true sig2;
-						self#texpr rvalue_any e2;
+						(match (get_unboxed_type sig1), sig2 with
+						| (TFloat | TDouble as unboxed_sig1), TInt ->
+							jm#cast ~not_null:true unboxed_sig1;
+							self#texpr rvalue_any e2;
+							jm#cast ~not_null:true unboxed_sig1
+						| _ ->
+							jm#cast ~not_null:true sig2;
+							self#texpr rvalue_any e2
+						);
 						self#boolop (self#do_compare op)
 					);
 				CmpNormal(CmpEq,TBool)
 			| true,false ->
 				self#texpr rvalue_any e1;
-				self#texpr rvalue_any e2;
+				let cast =
+					match sig1, (get_unboxed_type sig2) with
+					| TInt, (TFloat | TDouble as unboxed_sig2) ->
+						jm#cast ~not_null:true unboxed_sig2;
+						self#texpr rvalue_any e2;
+						(fun() -> jm#cast ~not_null:true unboxed_sig2)
+					| _ ->
+						self#texpr rvalue_any e2;
+						(fun() -> jm#cast ~not_null:true sig1)
+				in
 				jm#get_code#dup;
 				jm#if_then_else
 					(self#if_not_null sig2)
@@ -1047,7 +1083,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 						jm#get_code#bconst (op = CmpNe);
 					)
 					(fun () ->
-						jm#cast ~not_null:true sig1;
+						cast();
 						self#boolop (self#do_compare op)
 					);
 				CmpNormal(CmpEq,TBool)
@@ -1961,9 +1997,9 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 			List.iter (self#texpr ret) el
 		| TArrayDecl el ->
 			begin match follow e.etype with
-			| TInst({cl_path = ([],"Array")},[t]) ->
+			| TInst({cl_path = (["haxe";"root"],"Array")},[t]) ->
 				self#new_native_array (jsignature_of_type (self#mknull t)) el;
-				jm#invokestatic ([],"Array") "ofNative" (method_sig [array_sig object_sig] (Some (object_path_sig ([],"Array"))));
+				jm#invokestatic (["haxe";"root"],"Array") "ofNative" (method_sig [array_sig object_sig] (Some (object_path_sig (["haxe";"root"],"Array"))));
 				self#cast e.etype
 			| _ ->
 				assert false
@@ -1974,7 +2010,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 			self#texpr ret e2;
 		| TArray(e1,e2) ->
 			begin match follow e1.etype with
-			| TInst({cl_path = ([],"Array")} as c,[t]) ->
+			| TInst({cl_path = (["haxe";"root"],"Array")} as c,[t]) ->
 				self#texpr rvalue_any e1;
 				self#texpr (rvalue_sig TInt) e2;
 				jm#cast TInt;
@@ -2253,12 +2289,12 @@ class tclass_to_jvm gctx c = object(self)
 			in
 			if !has_type_param then Some t else None
 		in
-		let make_bridge cf cf_impl t =
+		let make_bridge cf_impl t =
 			let jsig = jsignature_of_type t in
-			if not (jc#has_method cf.cf_name jsig) then begin
+			if not (jc#has_method cf_impl.cf_name jsig) then begin
 				begin match follow t with
 				| TFun(tl,tr) ->
-					let jm = jc#spawn_method cf.cf_name jsig [MPublic;MSynthetic;MBridge] in
+					let jm = jc#spawn_method cf_impl.cf_name jsig [MPublic;MSynthetic;MBridge] in
 					jm#load_this;
 					let jsig_impl = jsignature_of_type cf_impl.cf_type in
 					let jsigs,_ = match jsig_impl with TMethod(jsigs,jsig) -> jsigs,jsig | _ -> assert false in
@@ -2267,7 +2303,7 @@ class tclass_to_jvm gctx c = object(self)
 						load();
 						jm#cast jsig;
 					) tl jsigs;
-					jm#invokevirtual c.cl_path cf.cf_name jsig_impl;
+					jm#invokevirtual c.cl_path cf_impl.cf_name jsig_impl;
 					if not (ExtType.is_void (follow tr)) then jm#cast (jsignature_of_type tr);
 					jm#return;
 				| _ ->
@@ -2275,27 +2311,35 @@ class tclass_to_jvm gctx c = object(self)
 				end
 			end
 		in
-		let check cf cf_impl map_type =
-			match cf.cf_kind with
-			| Method (MethNormal | MethInline) ->
-				begin match map_type_params cf.cf_type with
-				| Some t -> make_bridge cf cf_impl t
-				| None -> ()
-				end
-			| _ ->
-				()
+		let check is_interface cf cf_impl =
+			match map_type_params cf.cf_type with
+			| Some t ->
+				make_bridge cf_impl t
+			| None ->
+				(* If we implement an interface with variance, we need a bridge method too (#8528). *)
+				if is_interface && not (type_iseq cf.cf_type cf_impl.cf_type) then make_bridge cf_impl cf.cf_type
 		in
-		let check cf cf_impl map_type =
-			check cf cf_impl map_type;
-			List.iter (fun cf -> check cf cf_impl map_type) cf.cf_overloads
+		let check is_interface cf cf_impl =
+			check is_interface cf cf_impl;
+			(* TODO: I think this is incorrect... have to investigate though *)
+			(* List.iter (fun cf -> check is_interface cf cf_impl) cf.cf_overloads *)
 		in
 		let rec loop map_type c_int =
 			List.iter (fun (c_int,tl) ->
 				let map_type t = apply_params c_int.cl_params tl (map_type t) in
 				List.iter (fun cf ->
-					match raw_class_field (fun cf -> map_type cf.cf_type) c (List.map snd c.cl_params) cf.cf_name with
-					| Some(c',_),_,cf_impl when c' == c -> check cf cf_impl map_type
-					| _ -> ()
+					match cf.cf_kind,raw_class_field (fun cf -> map_type cf.cf_type) c (List.map snd c.cl_params) cf.cf_name with
+					| (Method (MethNormal | MethInline)),(Some(c',_),_,cf_impl) when c' == c ->
+						let tl = match follow (map_type cf.cf_type) with
+							| TFun(tl,_) -> tl
+							| _ -> assert false
+						in
+						begin match find_overload_rec' false map_type c cf.cf_name (List.map (fun (_,_,t) -> Texpr.Builder.make_null t null_pos) tl) with
+							| Some(_,cf_impl) -> check true cf cf_impl
+							| None -> ()
+						end;
+					| _ ->
+						()
 				) c_int.cl_ordered_fields;
 				loop map_type c_int
 			) c_int.cl_implements
@@ -2306,9 +2350,9 @@ class tclass_to_jvm gctx c = object(self)
 			()
 		| fields,Some(c_sup,tl) ->
 			List.iter (fun cf_impl ->
-				match raw_class_field (fun cf -> apply_params c_sup.cl_params tl cf.cf_type) c_sup tl cf_impl.cf_name with
-				| Some(c,tl),_,cf -> check cf cf_impl (apply_params c.cl_params tl)
-				| _ -> assert false
+				match cf_impl.cf_kind,raw_class_field (fun cf -> apply_params c_sup.cl_params tl cf.cf_type) c_sup tl cf_impl.cf_name with
+				| (Method (MethNormal | MethInline)),(Some(c,tl),_,cf) -> check false cf cf_impl
+				| _ -> ()
 			) fields
 		| _ ->
 			assert false
@@ -2502,9 +2546,9 @@ class tclass_to_jvm gctx c = object(self)
 			let jsig = method_sig [array_sig string_sig] None in
 			let jm = jc#spawn_method "main" jsig [MPublic;MStatic] in
 			let _,load,_ = jm#add_local "args" (TArray(string_sig,None)) VarArgument in
-			if has_feature gctx.com "Sys.args" then begin
+			if has_feature gctx.com "haxe.root.Sys.args" then begin
 				load();
-				jm#putstatic ([],"Sys") "_args" (TArray(string_sig,None))
+				jm#putstatic (["haxe";"root"],"Sys") "_args" (TArray(string_sig,None))
 			end;
 			jm#invokestatic (["haxe"; "java"], "Init") "init" (method_sig [] None);
 			jm#invokestatic jc#get_this_path "main" (method_sig [] None);
@@ -2931,9 +2975,17 @@ module Preprocessor = struct
 			in
 			List.iter field (cf :: cf.cf_overloads)
 
+	let make_root path =
+		["haxe";"root"],snd path
+
 	let preprocess gctx =
-		List.iter (function
-			| TClassDecl c when debug_path c.cl_path && not c.cl_interface -> preprocess_class gctx c
+		List.iter (fun mt ->
+			match mt with
+			| TClassDecl c ->
+				if fst c.cl_path = [] then c.cl_path <- make_root c.cl_path;
+				if debug_path c.cl_path && not c.cl_interface then preprocess_class gctx c
+			| TEnumDecl en ->
+				if fst en.e_path = [] then en.e_path <- make_root en.e_path;
 			| _ -> ()
 		) gctx.com.types
 end
@@ -2946,7 +2998,13 @@ let file_name_and_extension file =
 let generate com =
 	mkdir_from_path com.file;
 	let jar_name,manifest_suffix = match com.main_class with
-		| Some path -> snd path,"\nMain-Class: " ^ (s_type_path path)
+		| Some path ->
+			let pack = match fst path with
+				| [] -> ["haxe";"root"]
+				| pack -> pack
+			in
+			let name = snd path in
+			name,"\nMain-Class: " ^ (s_type_path (pack,name))
 		| None -> "jar",""
 	in
 	let jar_name = if com.debug then jar_name ^ "-Debug" else jar_name in
@@ -2968,13 +3026,13 @@ let generate com =
 		}
 	} in
 	Std.finally (Timer.timer ["generate";"java";"preprocess"]) Preprocessor.preprocess gctx;
-	let class_paths = ExtList.List.filter_map (fun (file,std,_,_,_) ->
-		if std then None
+	let class_paths = ExtList.List.filter_map (fun java_lib ->
+		if java_lib#has_flag NativeLibraries.FlagIsStd then None
 		else begin
 			let dir = Printf.sprintf "%slib/" jar_dir in
 			Path.mkdir_from_path dir;
-			let name = file_name_and_extension file in
-			let ch_in = open_in_bin file in
+			let name = file_name_and_extension java_lib#get_file_path in
+			let ch_in = open_in_bin java_lib#get_file_path in
 			let ch_out = open_out_bin (Printf.sprintf "%s%s" dir name) in
 			let b = IO.read_all (IO.input_channel ch_in) in
 			output_string ch_out b;
@@ -2982,7 +3040,7 @@ let generate com =
 			close_out ch_out;
 			Some (Printf.sprintf "lib/%s" name)
 		end
-	) com.java_libs in
+	) com.native_libs.java_libs in
 	let manifest_content =
 		"Manifest-Version: 1.0\n" ^
 		(match class_paths with [] -> "" | _ -> "Class-Path: " ^ (String.concat " " class_paths ^ "\n")) ^

+ 20 - 1
src/generators/genphp7.ml

@@ -310,6 +310,11 @@ let is_string_type t = match follow t with TInst ({ cl_path = ([], "String") },
 *)
 let is_string expr = is_string_type expr.etype
 
+(**
+	Check if specified type is Array
+*)
+let is_array_type t = match follow t with TInst ({ cl_path = ([], "Array") }, _) -> true | _ -> false
+
 (**
 	Check if specified type represents a function
 *)
@@ -1606,6 +1611,8 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 					vars#used var.v_name;
 					self#write ("$" ^ var.v_name)
 				| TArray (target, index) -> self#write_expr_array_access target index
+				| TBinop (OpAssign, { eexpr = TArray (target, index) }, value) when is_array_type target.etype ->
+					self#write_expr_set_array_item target index value
 				| TBinop (operation, expr1, expr2) when needs_dereferencing (is_assignment_binop operation) expr1 ->
 					self#write_expr { expr with eexpr = TBinop (operation, self#dereference expr1, expr2) }
 				| TBinop (operation, expr1, expr2) -> self#write_expr_binop operation expr1 expr2
@@ -1720,6 +1727,14 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 					List.iter write_field fields;
 					self#indent_less;
 					self#write_with_indentation "]"
+		(**
+			Writes `target[index] = value` assuming `target` is of `Array` type
+		*)
+		method write_expr_set_array_item target index value =
+			self#write_expr target;
+			self#write "->offsetSet(";
+			write_args self#write self#write_expr [index; value];
+			self#write ")"
 		(**
 			Writes TArray to output buffer
 		*)
@@ -2082,7 +2097,11 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 				self#write ")"
 			in
 			let write_for_concat expr =
-				if ((is_constant expr) && not (is_constant_null expr)) || (is_concatenation expr) then
+				if ((is_constant expr) && not (is_constant_null expr))
+					|| (is_concatenation expr)
+					|| is_php_global expr
+					|| is_php_class_const expr
+				then
 					self#write_expr expr
 				else begin
 					self#write "(";

+ 1 - 1
src/generators/genpy.ml

@@ -1145,7 +1145,7 @@ module Printer = struct
 						| None -> ""
 						| Some ct ->
 							had_value := true;
-							Printf.sprintf " = %s" (print_expr pctx ct)
+							" = None"
 		) args in
 		String.concat "," sl
 

+ 23 - 9
src/generators/genswf.ml

@@ -24,6 +24,7 @@ open Type
 open Common
 open Ast
 open Globals
+open NativeLibraries
 
 let tag ?(ext=false) d = {
 	tid = 0;
@@ -276,12 +277,14 @@ let build_swf9 com file swc =
 					let ttf = try TTFParser.parse ch with e -> abort ("Error while parsing font " ^ file ^ " : " ^ Printexc.to_string e) p in
 					close_in ch;
 					let get_string e = match fst e with
-						| EConst (String s) -> Some s
+						| EConst (String s) -> s
 						| _ -> raise Not_found
 					in
 					let ttf_config = {
 						ttfc_range_str = "";
 						ttfc_font_name = None;
+						ttfc_font_weight = TFWRegular;
+						ttfc_font_posture = TFPNormal;
 					} in
 					begin match args with
 						| (EConst (String str),_) :: _ -> ttf_config.ttfc_range_str <- str;
@@ -291,8 +294,19 @@ let build_swf9 com file swc =
 						| _ :: [e] ->
 							begin match fst e with
 								| EObjectDecl fl ->
-									begin try ttf_config.ttfc_font_name <- get_string (Expr.field_assoc "fontName" fl)
-									with Not_found -> () end
+									(try ttf_config.ttfc_font_name <- Some(get_string (Expr.field_assoc "fontName" fl)) with Not_found -> ());
+									(try ttf_config.ttfc_font_weight <- (
+										match get_string (Expr.field_assoc "fontWeight" fl) with
+										| "regular" -> TFWRegular
+										| "bold" -> TFWBold
+										| _ -> abort "Invalid fontWeight value. Must be `regular` or `bold`." p
+									) with Not_found -> ());
+									(try ttf_config.ttfc_font_posture <- (
+										match get_string (Expr.field_assoc "fontStyle" fl) with
+										| "normal" -> TFPNormal
+										| "italic" -> TFPItalic
+										| _ -> abort "Invalid fontStyle value. Must be `normal` or `italic`." p
+									) with Not_found -> ());
 								| _ ->
 									()
 							end
@@ -557,8 +571,8 @@ let generate swf_header com =
 	(* list exports *)
 	let exports = Hashtbl.create 0 in
 	let toremove = ref [] in
-	List.iter (fun (file,lib,_) ->
-		let _, tags = lib() in
+	List.iter (fun swf_lib ->
+		let _, tags = swf_lib#get_data in
 		List.iter (fun t ->
 			match t.tdata with
 			| TExport l -> List.iter (fun e -> Hashtbl.add exports e.exp_name ()) l
@@ -584,7 +598,7 @@ let generate swf_header com =
 				) el
 			| _ -> ()
 		) tags;
-	) com.swf_libs;
+	) com.native_libs.swf_libs;
 	(* build haxe swf *)
 	let tags = build_swf9 com file swc in
 	let header, bg = (match swf_header with None -> default_header com | Some h -> convert_header com h) in
@@ -625,11 +639,11 @@ let generate swf_header com =
 	let swf = header, fattr @ meta_data @ bg :: scene :: debug @ swf_script_limits @ tags @ [tag TShowFrame] in
 	(* merge swf libraries *)
 	let priority = ref (swf_header = None) in
-	let swf = List.fold_left (fun swf (file,lib,cl) ->
-		let swf = merge com file !priority swf (SwfLoader.remove_classes toremove lib cl) in
+	let swf = List.fold_left (fun swf swf_lib ->
+		let swf = merge com file !priority swf (SwfLoader.remove_classes toremove swf_lib#get_data swf_lib#list_modules) in
 		priority := false;
 		swf
-	) swf com.swf_libs in
+	) swf com.native_libs.swf_libs in
 	let swf = match swf with
 	| header,tags when Common.defined com Define.SwfPreloaderFrame ->
 		let rec loop l =

+ 7 - 2
src/generators/genswf9.ml

@@ -200,7 +200,6 @@ let rec follow_basic t =
 		| TAbstract ({ a_path = ([],"Bool") },[])
 		| TInst ({ cl_path = (["haxe"],"Int32") },[]) -> t
 		| t -> t)
-	| TType ({ t_path = ["flash";"utils"],"Object" },[])
 	| TType ({ t_path = ["flash";"utils"],"Function" },[])
 	| TType ({ t_path = [],"UInt" },[]) ->
 		t
@@ -231,6 +230,8 @@ let rec type_id ctx t =
 			type_path ctx c.cl_path)
 	| TAbstract ({ a_path = [],"Null"},_) ->
 		HMPath ([],"Object")
+	| TAbstract ({ a_path = ["flash"],"AnyType"},_) ->
+		HMAny
 	| TAbstract (a,_) when Meta.has Meta.CoreType a.a_meta ->
 		type_path ctx a.a_path
 	| TFun _ | TType ({ t_path = ["flash";"utils"],"Function" },[]) ->
@@ -264,6 +265,8 @@ let classify ctx t =
 		KBool
 	| TAbstract ({ a_path = [],"Void" },_) | TEnum ({ e_path = [],"Void" },_) ->
 		KDynamic
+	| TAbstract ({ a_path = ["flash"],"AnyType" },_) ->
+		KDynamic
 	| TEnum ({ e_path = ["flash"],"XmlType"; e_extern = true },_) ->
 		KType (HMPath ([],"String"))
 	| TEnum (e,_) ->
@@ -276,7 +279,7 @@ let classify ctx t =
 		(match !(a.a_status) with
 		| Statics _ -> KNone
 		| _ -> KDynamic)
-	| TType ({ t_path = ["flash";"utils"],"Object" },[]) ->
+	| TAbstract ({ a_path = ["flash";"utils"],"Object" },[]) ->
 		KType (HMPath ([],"Object"))
 	| TInst _ | TAbstract _ ->
 		KType (type_id ctx t)
@@ -1034,6 +1037,8 @@ let rec gen_type ctx t =
 		write ctx (HGetLex t);
 		List.iter (gen_type ctx) tl;
 		write ctx (HApplyType (List.length tl));
+	| HMAny ->
+		write ctx (HNull)
 	| _ ->
 		write ctx (HGetLex t)
 

+ 19 - 0
src/generators/jvm/jvmAttribute.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open JvmGlobals
 open JvmData
 open JvmVerificationTypeInfo

+ 19 - 0
src/generators/jvm/jvmBuilder.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open JvmGlobals
 open JvmData
 open JvmSignature

+ 19 - 0
src/generators/jvm/jvmClass.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open JvmGlobals
 open JvmData
 open JvmSignature

+ 19 - 0
src/generators/jvm/jvmCode.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open JvmGlobals
 open JvmData
 open JvmSignature

+ 19 - 0
src/generators/jvm/jvmConstantPool.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open IO
 open IO.BigEndian
 open JvmGlobals

+ 21 - 2
src/generators/jvm/jvmData.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open JvmGlobals
 
 (* Low-level data that is written out. *)
@@ -266,8 +285,8 @@ and jopcode =
 	(* other *)
 	| OpAthrow
 	| OpIinc of jbyte * jbyte
-	| OpLookupswitch of int (* num pad bytes *) * jbranchoffset ref (* default *) * (int * jbranchoffset ref) array
-	| OpTableswitch of int (* num pad bytes *) * jbranchoffset ref (* default *) * int (* low *) * int (* high *) * jbranchoffset ref array
+	| OpLookupswitch of int (* num pad bytes *) * jbranchoffset ref (* default *) * (Int32.t * jbranchoffset ref) array
+	| OpTableswitch of int (* num pad bytes *) * jbranchoffset ref (* default *) * Int32.t (* low *) * Int32.t (* high *) * jbranchoffset ref array
 	| OpMonitorenter
 	| OpMonitorexit
 	| OpRet of jbyte

+ 19 - 0
src/generators/jvm/jvmDebug.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open JvmGlobals
 open JvmData
 

+ 21 - 0
src/generators/jvm/jvmGlobals.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 type jvm_constant_pool_index = int
 
 (* Constants *)
@@ -30,6 +49,8 @@ type numeric_range =
 	| Int16Range
 	| Int32Range
 
+let i320xFF = Int32.of_int 0xFF
+
 let get_numeric_range i =
 	if i >= -128 && i <= 127 then Int8Range
 	else if i >= -32768 && i <= 32767 then Int16Range

+ 30 - 11
src/generators/jvm/jvmMethod.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open Globals
 open JvmGlobals
 open JvmData
@@ -542,28 +561,28 @@ class builder jc name jsig = object(self)
 				def,cases
 		in
 		let flat_cases = DynArray.create () in
-		let case_lut = ref IntMap.empty in
+		let case_lut = ref Int32Map.empty in
 		let fp = code#get_fp in
-		let imin = ref max_int in
-		let imax = ref min_int in
+		let imin = ref Int32.min_int in
+		let imax = ref Int32.max_int in
 		let cases = List.map (fun (il,f) ->
 			let rl = List.map (fun i32 ->
 				let r = ref fp in
-				let i = Int32.to_int i32 in
-				if i < !imin then imin := i;
-				if i > !imax then imax := i;
-				DynArray.add flat_cases (i,r);
-				case_lut := IntMap.add i r !case_lut;
+				if i32 < !imin then imin := i32;
+				if i32 > !imax then imax := i32;
+				DynArray.add flat_cases (i32,r);
+				case_lut := Int32Map.add i32 r !case_lut;
 				r
 			) il in
 			(rl,f)
 		) cases in
 		let offset_def = ref fp in
 		(* No idea what's a good heuristic here... *)
-		let use_tableswitch = (!imax - !imin) < (DynArray.length flat_cases + 10) in
+		let diff = Int32.sub !imax !imin in
+		let use_tableswitch = diff < (Int32.of_int (DynArray.length flat_cases + 10)) && diff >= Int32.zero (* #8388 *) in
 		if use_tableswitch then begin
-			let offsets = Array.init (!imax - !imin + 1) (fun i ->
-				try IntMap.find (i + !imin) !case_lut
+			let offsets = Array.init (Int32.to_int (Int32.sub !imax !imin) + 1) (fun i ->
+				try Int32Map.find (Int32.add (Int32.of_int i) !imin) !case_lut
 				with Not_found -> offset_def
 			) in
 			code#tableswitch offset_def !imin !imax offsets

+ 19 - 0
src/generators/jvm/jvmSignature.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open JvmGlobals
 
 type jpath = (string list) * string

+ 19 - 0
src/generators/jvm/jvmVerificationTypeInfo.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open JvmGlobals
 open JvmSignature
 

+ 29 - 3
src/generators/jvm/jvmWriter.ml

@@ -1,3 +1,22 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2019  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
 open JvmGlobals
 open JvmData
 
@@ -48,6 +67,7 @@ let write_exception ch jvme =
 
 let write_opcode ch code =
   let w = write_byte ch in
+  let wr i32 = write_byte ch (Int32.to_int i32) in
   (* TODO: probably don't need these *)
   let bp i =
     w ((i lsr 8) land 0xFF);
@@ -59,6 +79,12 @@ let write_opcode ch code =
     w ((i lsr 8) land 0xFF);
     w (i land 0xFF);
   in
+  let b4r i32 =
+    wr (Int32.logand (Int32.shift_right_logical i32 24) i320xFF);
+    wr (Int32.logand (Int32.shift_right_logical i32 16) i320xFF);
+    wr (Int32.logand (Int32.shift_right_logical i32 8) i320xFF);
+    wr (Int32.logand i32 i320xFF);
+  in
   let rec loop code = match code with
     (* double *)
     | OpD2f -> w 0x90
@@ -280,15 +306,15 @@ let write_opcode ch code =
 		b4 !def;
 		b4 (Array.length pairs);
 		Array.iter (fun (i,offset) ->
-			b4 i;
+			b4r i;
 			b4 !offset
 		) pairs;
     | OpTableswitch(pad,def,low,high,offsets) ->
 		w 0xaa;
 		if pad > 0 then for i = 0 to pad -1 do w 0 done;
 		b4 !def;
-		b4 low;
-		b4 high;
+		b4r low;
+		b4r high;
 		Array.iter (fun offset ->
 			b4 !offset
 		) offsets;

+ 30 - 3
src/macro/eval/evalContext.ml

@@ -203,6 +203,34 @@ class eval_debug_context = object(self)
 
 end
 
+class static_prototypes = object(self)
+	val mutable prototypes : vprototype IntMap.t = IntMap.empty
+	val mutable inits : (bool ref * vprototype * (vprototype -> unit) list) IntMap.t = IntMap.empty
+
+	method add proto =
+		prototypes <- IntMap.add proto.ppath proto prototypes
+
+	method remove path =
+		inits <- IntMap.remove path inits;
+		prototypes <- IntMap.remove path prototypes
+
+	method set_needs_reset =
+		IntMap.iter (fun path (needs_reset, _, _) -> needs_reset := true) inits
+
+	method add_init proto delays =
+		inits <- IntMap.add proto.ppath (ref false, proto, delays) inits
+
+	method get path =
+		(try
+			let (needs_reset, proto, delays) = IntMap.find path inits in
+			if !needs_reset then begin
+				needs_reset := false;
+				List.iter (fun f -> f proto) delays
+			end
+		with Not_found -> ());
+		IntMap.find path prototypes
+end
+
 type exception_mode =
 	| CatchAll
 	| CatchUncaught
@@ -251,10 +279,9 @@ and context = {
 	mutable string_prototype : vprototype;
 	mutable vector_prototype : vprototype;
 	mutable instance_prototypes : vprototype IntMap.t;
-	mutable static_prototypes : vprototype IntMap.t;
+	mutable static_prototypes : static_prototypes;
 	mutable constructors : value Lazy.t IntMap.t;
 	get_object_prototype : 'a . context -> (int * 'a) list -> vprototype * (int * 'a) list;
-	mutable static_inits : (vprototype * (vprototype -> unit) list) IntMap.t;
 	(* eval *)
 	toplevel : value;
 	eval : eval;
@@ -440,7 +467,7 @@ let pop_environment ctx env =
 (* Prototypes *)
 
 let get_static_prototype_raise ctx path =
-	IntMap.find path ctx.static_prototypes
+	ctx.static_prototypes#get path
 
 let get_static_prototype ctx path p =
 	try get_static_prototype_raise ctx path

+ 28 - 11
src/macro/eval/evalDebugMisc.ml

@@ -164,7 +164,7 @@ let resolve_ident ctx env s =
 		end
 	with Not_found -> try
 		(* 4. Type *)
-		VPrototype (IntMap.find key ctx.static_prototypes)
+		VPrototype (get_static_prototype_raise ctx key)
 	with Not_found -> try
 		(* 5. Toplevel *)
 		EvalField.field_raise ctx.toplevel key
@@ -224,17 +224,25 @@ let rec expr_to_value ctx env e =
 			end
 		| EField(e1,s) ->
 			let v1 = loop e1 in
-			let s = hash s in
+			let s' = hash s in
 			begin match v1 with
 			| VEnumValue ve ->
 				begin try
-					let i = find_enum_field_by_name ve s in
+					let i = find_enum_field_by_name ve s' in
 					ve.eargs.(i)
 				with Not_found ->
 					vnull
 				end
 			| _ ->
-				let v = EvalField.field v1 s in
+				let v = try
+					EvalField.field_raise v1 s'
+				with Not_found -> try
+					(* Maybe we have a getter? (#8599) *)
+					let vf = EvalField.field v1 (hash ("get_" ^ s)) in
+					safe_call env.env_eval (EvalPrinting.call_value_on v1 vf) []
+				with _ ->
+					vnull
+				in
 				v
 			end
 		| EArrayDecl el ->
@@ -248,7 +256,6 @@ let rec expr_to_value ctx env e =
 			| OpAssign ->
 				let v2 = loop e2 in
 				write_expr ctx env e1 v2;
-				v2
 			| OpAssignOp op ->
 				raise Exit (* Nobody does that, right? *)
 			| OpBoolAnd ->
@@ -360,23 +367,32 @@ let rec expr_to_value ctx env e =
 and write_expr ctx env expr value =
 	begin match fst expr with
 		| EField(e1,s) ->
-			let s = hash s in
+			let s' = hash s in
 			let v1 = expr_to_value ctx env e1 in
 			begin match v1 with
 			| VEnumValue ve ->
 				begin try
-					let i = find_enum_field_by_name ve s in
-					ve.eargs.(i) <- value
+					let i = find_enum_field_by_name ve s' in
+					ve.eargs.(i) <- value;
+					value
 				with Not_found ->
-					()
+					value
 				end
 			| _ ->
-				set_field v1 s value;
+				try
+					set_field v1 s' value;
+					value;
+				with Not_found -> try
+					let vf = EvalField.field v1 (hash ("set_" ^ s)) in
+					safe_call env.env_eval (EvalPrinting.call_value_on v1 vf) [value]
+				with _ ->
+					value
 			end
 		| EConst (Ident s) ->
 			begin try
 				let slot = get_var_slot_by_name env false env.env_debug.scopes s in
 				env.env_locals.(slot) <- value;
+				value
 			with Not_found ->
 				raise Exit
 			end
@@ -389,7 +405,8 @@ and write_expr ctx env expr value =
 				| VVector vv -> Array.set vv idx value
 				| VEnumValue ev -> Array.set ev.eargs idx value
 				| _ -> raise Exit
-			end
+			end;
+			value
 		| _ ->
 			raise Exit
 	end

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

@@ -120,11 +120,10 @@ let create com api is_macro =
 		string_prototype = fake_proto key_String;
 		array_prototype = fake_proto key_Array;
 		vector_prototype = fake_proto key_eval_Vector;
-		static_prototypes = IntMap.empty;
+		static_prototypes = new static_prototypes;
 		instance_prototypes = IntMap.empty;
 		constructors = IntMap.empty;
 		get_object_prototype = get_object_prototype;
-		static_inits = IntMap.empty;
 		(* eval *)
 		toplevel = 	vobject {
 			ofields = [||];
@@ -375,7 +374,7 @@ let setup get_api =
 
 let do_reuse ctx api =
 	ctx.curapi <- api;
-	IntMap.iter (fun _ (proto,delays) -> List.iter (fun f -> f proto) delays) ctx.static_inits
+	ctx.static_prototypes#set_needs_reset
 
 let set_error ctx b =
 	(* TODO: Have to reset this somewhere if running compilation server. But where... *)

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

@@ -159,7 +159,7 @@ module PrototypeBuilder = struct
 		proto.pvalue <- vprototype proto;
 		(* Register the prototype. *)
 		if pctx.is_static then
-			ctx.static_prototypes <- IntMap.add pctx.key proto ctx.static_prototypes
+			ctx.static_prototypes#add proto
 		else begin
 			ctx.instance_prototypes <- IntMap.add pctx.key proto ctx.instance_prototypes;
 			if pctx.key = key_String then ctx.string_prototype <- proto
@@ -307,7 +307,7 @@ let add_types ctx types ready =
 			false
 		with Not_found ->
 			ctx.instance_prototypes <- IntMap.remove key ctx.instance_prototypes;
-			ctx.static_prototypes <- IntMap.remove key ctx.static_prototypes;
+			ctx.static_prototypes#remove key;
 			ctx.constructors <- IntMap.remove key ctx.constructors;
 			ready mt;
 			ctx.type_cache <- IntMap.add key mt ctx.type_cache;
@@ -355,7 +355,7 @@ let add_types ctx types ready =
 		| _ ->
 			DynArray.add fl_static_init (proto,delays);
 			let non_persistent_delays = ExtList.List.filter_map (fun (persistent,f) -> if not persistent then Some f else None) delays in
-			ctx.static_inits <- IntMap.add proto.ppath (proto,non_persistent_delays) ctx.static_inits;
+			ctx.static_prototypes#add_init proto non_persistent_delays;
 	) fl_static;
 	(* 4. Initialize static fields. *)
 	DynArray.iter (fun (proto,delays) -> List.iter (fun (_,f) -> f proto) delays) fl_static_init;

+ 43 - 14
src/macro/eval/evalStdLib.ml

@@ -674,6 +674,8 @@ module StdCrc32 = struct
 end
 
 module StdDate = struct
+	open Unix
+
 	let encode_date d = encode_instance key_Date ~kind:(IDate d)
 
 	let this vthis = match vthis with
@@ -688,29 +690,33 @@ module StdDate = struct
 		| 19 ->
 			let r = Str.regexp "^\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\) \\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)$" in
 			if not (Str.string_match r s 0) then exc_string ("Invalid date format : " ^ s);
-			let t = catch_unix_error Unix.localtime (Unix.time()) in
-			let t = { t with
+			let t = {
 				tm_year = int_of_string (Str.matched_group 1 s) - 1900;
 				tm_mon = int_of_string (Str.matched_group 2 s) - 1;
 				tm_mday = int_of_string (Str.matched_group 3 s);
 				tm_hour = int_of_string (Str.matched_group 4 s);
 				tm_min = int_of_string (Str.matched_group 5 s);
 				tm_sec = int_of_string (Str.matched_group 6 s);
+				tm_wday = 0;
+				tm_yday = 0;
+				tm_isdst = false;
 			} in
-			encode_date (fst (catch_unix_error Unix.mktime t))
+			encode_date (fst (catch_unix_error mktime t))
 		| 10 ->
 			let r = Str.regexp "^\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\)$" in
 			if not (Str.string_match r s 0) then exc_string ("Invalid date format : " ^ s);
-			let t = catch_unix_error Unix.localtime (Unix.time()) in
-			let t = { t with
+			let t = {
 				tm_year = int_of_string (Str.matched_group 1 s) - 1900;
 				tm_mon = int_of_string (Str.matched_group 2 s) - 1;
 				tm_mday = int_of_string (Str.matched_group 3 s);
 				tm_hour = 0;
 				tm_min = 0;
 				tm_sec = 0;
+				tm_wday = 0;
+				tm_yday = 0;
+				tm_isdst = false;
 			} in
-			encode_date (fst (catch_unix_error Unix.mktime t))
+			encode_date (fst (catch_unix_error mktime t))
 		| 8 ->
 			let r = Str.regexp "^\\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)$" in
 			if not (Str.string_match r s 0) then exc_string ("Invalid date format : " ^ s);
@@ -723,15 +729,29 @@ module StdDate = struct
 			exc_string ("Invalid date format : " ^ s)
 	)
 
-	let getDate = vifun0 (fun vthis -> vint (catch_unix_error Unix.localtime (this vthis)).tm_mday)
-	let getDay = vifun0 (fun vthis -> vint (catch_unix_error Unix.localtime (this vthis)).tm_wday)
-	let getFullYear = vifun0 (fun vthis -> vint (((catch_unix_error Unix.localtime (this vthis)).tm_year) + 1900))
-	let getHours = vifun0 (fun vthis -> vint (catch_unix_error Unix.localtime (this vthis)).tm_hour)
-	let getMinutes = vifun0 (fun vthis -> vint (catch_unix_error Unix.localtime (this vthis)).tm_min)
-	let getMonth = vifun0 (fun vthis -> vint (catch_unix_error Unix.localtime (this vthis)).tm_mon)
-	let getSeconds = vifun0 (fun vthis -> vint (catch_unix_error Unix.localtime (this vthis)).tm_sec)
+	let getDate = vifun0 (fun vthis -> vint (catch_unix_error localtime (this vthis)).tm_mday)
+	let getDay = vifun0 (fun vthis -> vint (catch_unix_error localtime (this vthis)).tm_wday)
+	let getFullYear = vifun0 (fun vthis -> vint (((catch_unix_error localtime (this vthis)).tm_year) + 1900))
+	let getHours = vifun0 (fun vthis -> vint (catch_unix_error localtime (this vthis)).tm_hour)
+	let getMinutes = vifun0 (fun vthis -> vint (catch_unix_error localtime (this vthis)).tm_min)
+	let getMonth = vifun0 (fun vthis -> vint (catch_unix_error localtime (this vthis)).tm_mon)
+	let getSeconds = vifun0 (fun vthis -> vint (catch_unix_error localtime (this vthis)).tm_sec)
+	let getUTCDate = vifun0 (fun vthis -> vint (catch_unix_error gmtime (this vthis)).tm_mday)
+	let getUTCDay = vifun0 (fun vthis -> vint (catch_unix_error gmtime (this vthis)).tm_wday)
+	let getUTCFullYear = vifun0 (fun vthis -> vint (((catch_unix_error gmtime (this vthis)).tm_year) + 1900))
+	let getUTCHours = vifun0 (fun vthis -> vint (catch_unix_error gmtime (this vthis)).tm_hour)
+	let getUTCMinutes = vifun0 (fun vthis -> vint (catch_unix_error gmtime (this vthis)).tm_min)
+	let getUTCMonth = vifun0 (fun vthis -> vint (catch_unix_error gmtime (this vthis)).tm_mon)
+	let getUTCSeconds = vifun0 (fun vthis -> vint (catch_unix_error gmtime (this vthis)).tm_sec)
 	let getTime = vifun0 (fun vthis -> vfloat ((this vthis) *. 1000.))
-	let now = vfun0 (fun () -> encode_date (catch_unix_error Unix.time()))
+	let getTimezoneOffset = vifun0 (fun vthis ->
+		let tmLocal = catch_unix_error localtime (this vthis) in
+		let tmUTC = catch_unix_error gmtime (this vthis) in
+		let tsLocal = fst (catch_unix_error mktime tmLocal) in
+		let tsUTC = fst (catch_unix_error mktime tmUTC) in
+		vint (int_of_float ((tsUTC -. tsLocal) /. 60.))
+	)
+	let now = vfun0 (fun () -> encode_date (catch_unix_error time()))
 	let toString = vifun0 (fun vthis -> vstring (s_date (this vthis)))
 end
 
@@ -1169,6 +1189,7 @@ module StdFileSystem = struct
 
 	let patch_path s =
 		if String.length s > 1 && String.length s <= 3 && s.[1] = ':' then Path.add_trailing_slash s
+		else if s = "/" then "/"
 		else remove_trailing_slash s
 
 	let createDirectory = vfun1 (fun path ->
@@ -3312,7 +3333,15 @@ let init_standard_library builtins =
 		"getMinutes",StdDate.getMinutes;
 		"getMonth",StdDate.getMonth;
 		"getSeconds",StdDate.getSeconds;
+		"getUTCDate",StdDate.getUTCDate;
+		"getUTCDay",StdDate.getUTCDay;
+		"getUTCFullYear",StdDate.getUTCFullYear;
+		"getUTCHours",StdDate.getUTCHours;
+		"getUTCMinutes",StdDate.getUTCMinutes;
+		"getUTCMonth",StdDate.getUTCMonth;
+		"getUTCSeconds",StdDate.getUTCSeconds;
 		"getTime",StdDate.getTime;
+		"getTimezoneOffset",StdDate.getTimezoneOffset;
 		"toString",StdDate.toString;
 	];
 	init_fields builtins (["sys";"thread"],"Deque") [] [

+ 8 - 13
src/macro/macroApi.ml

@@ -1682,6 +1682,12 @@ let macro_api ccom get_api =
 			);
 			vnull
 		);
+		"flush_disk_cache", vfun0 (fun () ->
+			let com = (get_api()).get_com() in
+			Hashtbl.clear com.file_lookup_cache;
+			Hashtbl.clear com.readdir_cache;
+			vnull
+		);
 		"get_pos_infos", vfun1 (fun p ->
 			let p = decode_pos p in
 			encode_obj ["min",vint p.Globals.pmin;"max",vint p.Globals.pmax;"file",encode_string p.Globals.pfile]
@@ -1793,24 +1799,13 @@ let macro_api ccom get_api =
 			| None ->
 				());
 			Hashtbl.clear com.file_lookup_cache;
+			Hashtbl.clear com.readdir_cache;
 			vnull
 		);
 		"add_native_lib", vfun1 (fun file ->
 			let file = decode_string file in
 			let com = ccom() in
-			(match com.platform with
-			| Globals.Flash -> SwfLoader.add_swf_lib com file false
-			| Globals.Java -> Java.add_java_lib com file false
-			| Globals.Cs ->
-				let file, is_std = match ExtString.String.nsplit file "@" with
-					| [file] ->
-						file,false
-					| [file;"std"] ->
-						file,true
-					| _ -> failwith ("unsupported file@`std` format: " ^ file)
-				in
-				Dotnet.add_net_lib com file is_std
-			| _ -> failwith "Unsupported platform");
+			NativeLibraryHandler.add_native_lib com file false ();
 			vnull
 		);
 		"add_native_arg", vfun1 (fun arg ->

+ 0 - 1
src/optimization/analyzer.ml

@@ -1030,7 +1030,6 @@ module Run = struct
 	let run_on_field ctx config c cf = match cf.cf_expr with
 		| Some e when not (is_ignored cf.cf_meta) && not (Typecore.is_removable_field ctx cf) ->
 			let config = update_config_from_meta ctx.Typecore.com config cf.cf_meta in
-			(match e.eexpr with TFunction tf -> cf.cf_expr_unoptimized <- Some tf | _ -> ());
 			let actx = create_analyzer_context ctx.Typecore.com config e in
 			let debug() =
 				print_endline (Printf.sprintf "While analyzing %s.%s" (s_type_path c.cl_path) cf.cf_name);

+ 0 - 2
src/optimization/analyzerTexprTransformer.ml

@@ -173,8 +173,6 @@ let rec func ctx bb tf t p =
 			close_node g bb;
 			add_cfg_edge bb_func_end bb_next CFGGoto;
 			bb_next,ec
-		(*| TTypeExpr(TClassDecl {cl_kind = KAbstractImpl a}) when not (Meta.has Meta.RuntimeValue a.a_meta) ->
-			error "Cannot use abstract as value" e.epos*)
 		| TConst _ | TTypeExpr _ ->
 			bb,e
 		| TThrow _ | TReturn _ | TBreak | TContinue ->

+ 28 - 13
src/prebuild/main.ml

@@ -50,6 +50,13 @@ let as_bool = function
 	| JBool b -> Some b
 	| _ -> None
 
+let as_links = function
+	| JArray s -> Some (List.map (function
+			| JString s -> s
+			| _ -> raise (Prebuild_error "link should be a string")
+		) s)
+	| _ -> None
+
 let get_optional_field name map default fields =
 	try
 		let field = List.find (fun (n, _) -> n = name) fields in
@@ -71,11 +78,12 @@ let parse_define json =
 		| JObject fl -> fl
 		| _ -> raise (Prebuild_error "not an object")
 	in
-	(*name*) get_field "name" as_string fields,
-	(*define*) get_field "define" as_string fields,
-	(*doc*) get_field "doc" as_string fields,
-	(*params*) get_optional_field "params" as_params [] fields,
-	(*platforms*) get_optional_field "platforms" as_platforms [] fields
+	(* name *) get_field "name" as_string fields,
+	(* define *) get_field "define" as_string fields,
+	(* doc *) get_field "doc" as_string fields,
+	(* params *) get_optional_field "params" as_params [] fields,
+	(* platforms *) get_optional_field "platforms" as_platforms [] fields,
+	(* links *) get_optional_field "links" as_links [] fields
 
 let parse_meta json =
 	let fields = match json with
@@ -88,7 +96,8 @@ let parse_meta json =
 	(* params *) get_optional_field "params" as_params [] fields,
 	(* platforms *) get_optional_field "platforms" as_platforms [] fields,
 	(* targets *) get_optional_field "targets" as_targets [] fields,
-	(* internal *) get_optional_field "internal" as_bool false fields
+	(* internal *) get_optional_field "internal" as_bool false fields,
+	(* links *) get_optional_field "links" as_links [] fields
 
 let parse_file_array path map =
 	let file = open_in path in
@@ -106,27 +115,30 @@ let gen_platforms = function
 
 let gen_params = List.map (function param -> "HasParam \"" ^ param ^ "\"" )
 
+let gen_links = List.map (function link -> "Link \"" ^ link ^ "\"" )
+
 let gen_define_type defines =
-	String.concat "\n" (List.map (function (name, _, _, _, _) -> "\t| " ^ name) defines)
+	String.concat "\n" (List.map (function (name, _, _, _, _, _) -> "\t| " ^ name) defines)
 
 let gen_define_info defines =
 	let define_str = List.map (function
-		(name, define, doc, params, platforms) ->
+		(name, define, doc, params, platforms, links) ->
 			let platforms_str = gen_platforms platforms in
 			let params_str = gen_params params in
-			"\t| " ^ name ^ " -> \"" ^ define ^ "\",(" ^ (Printf.sprintf "%S" doc) ^ ",[" ^ (String.concat "; " (platforms_str @ params_str)) ^ "])"
+			let links_str = gen_links links in
+			"\t| " ^ name ^ " -> \"" ^ define ^ "\",(" ^ (Printf.sprintf "%S" doc) ^ ",[" ^ (String.concat "; " (platforms_str @ params_str @ links_str)) ^ "])"
 	) defines in
 	String.concat "\n" define_str
 
 let gen_meta_type metas =
 	String.concat "\n" (List.map (function
-		| ("InlineConstructorArgument", _, _, _, _, _, _) -> "\t| InlineConstructorArgument of int * int"
-		| (name, _, _, _, _, _, _) -> "\t| " ^ name
+		| ("InlineConstructorArgument", _, _, _, _, _, _, _) -> "\t| InlineConstructorArgument of int * int"
+		| (name, _, _, _, _, _, _, _) -> "\t| " ^ name
 	) metas)
 
 let gen_meta_info metas =
 	let meta_str = List.map (function
-		(name, metadata, doc, params, platforms, targets, internal) ->
+		(name, metadata, doc, params, platforms, targets, internal, links) ->
 			let platforms_str = gen_platforms platforms in
 			let params_str = gen_params params in
 			let targets_str = (match targets with
@@ -134,12 +146,13 @@ let gen_meta_info metas =
 				| targets -> ["UsedOn [" ^ (String.concat ";" targets) ^ "]"]
 			) in
 			let internal_str = if internal then ["UsedInternally"] else [] in
+			let links_str = gen_links links in
 			let name = (match name with
 				(* this is a hacky, I know *)
 				| "InlineConstructorArgument" -> "InlineConstructorArgument _"
 				| _ -> name
 			) in
-			"\t| " ^ name ^ " -> \"" ^ metadata ^ "\",(" ^ (Printf.sprintf "%S" doc) ^ ",[" ^ (String.concat "; " (platforms_str @ params_str @ targets_str @ internal_str)) ^ "])"
+			"\t| " ^ name ^ " -> \"" ^ metadata ^ "\",(" ^ (Printf.sprintf "%S" doc) ^ ",[" ^ (String.concat "; " (platforms_str @ params_str @ targets_str @ internal_str @ links_str)) ^ "])"
 	) metas in
 	String.concat "\n" meta_str
 
@@ -153,6 +166,7 @@ open Globals
 type define_parameter =
 	| HasParam of string
 	| Platforms of platform list
+	| Link of string
 
 "
 
@@ -176,6 +190,7 @@ type meta_parameter =
 	| Platforms of platform list
 	| UsedOn of meta_usage list
 	| UsedInternally
+	| Link of string
 
 "
 

+ 14 - 6
src/syntax/grammar.mly

@@ -1108,7 +1108,9 @@ and arrow_expr = parser
 
 and arrow_function p1 al er s =
 	let make e =
-		EFunction(None, { f_params = []; f_type = None; f_args = al; f_expr = Some (EReturn(Some e), (snd e));  }), punion p1 (pos e)
+		let p = pos e in
+		let return = (EMeta((Meta.ImplicitReturn, [], null_pos), (EReturn(Some e), p)), p) in
+		EFunction(None, { f_params = []; f_type = None; f_args = al; f_expr = Some return;  }), punion p1 p
 	in
 	List.iter (fun (_,_,ml,_,_) ->	match ml with
 		| (_,_,p) :: _ -> syntax_error (Custom "Metadata on arrow function arguments is not allowed") ~pos:(Some p) s ()
@@ -1260,11 +1262,17 @@ and expr = parser
 		let e2 = (match s with parser
 			| [< '(Kwd Else,_); e2 = secure_expr; s >] -> Some e2
 			| [< >] ->
-				match Stream.npeek 2 s with
-				| [(Semicolon,_); (Kwd Else,_)] ->
-					Stream.junk s;
-					Stream.junk s;
-					Some (secure_expr s)
+				(* We check this in two steps to avoid the lexer missing tokens (#8565). *)
+				match Stream.npeek 1 s with
+				| [(Semicolon,_)] ->
+					begin match Stream.npeek 2 s with
+					| [(Semicolon,_);(Kwd Else,_)] ->
+						Stream.junk s;
+						Stream.junk s;
+						Some (secure_expr s)
+					| _ ->
+						None
+					end
 				| _ ->
 					None
 		) in

+ 14 - 1
src/syntax/lexer.ml

@@ -198,7 +198,20 @@ let resolve_pos file =
 			| '\r' ->
 				ignore(input_char ch);
 				inc 2
-			| _ -> fun () -> 1
+			| c -> (fun () ->
+				let rec skip n =
+					if n > 0 then begin
+						ignore(input_char ch);
+						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
+			)
 		in
 		loop (p + i())
 	in

+ 2 - 2
src/syntax/parser.ml

@@ -118,11 +118,11 @@ let last_pos s = pos (last_token s)
 
 let next_token s = match Stream.peek s with
 	| Some (Eof,p) ->
-		(Eof,{p with pmax = max_int})
+		(Eof,p)
 	| Some tk -> tk
 	| None ->
 		let last_pos = pos (last_token s) in
-		(Eof,{last_pos with pmax = max_int})
+		(Eof,last_pos)
 
 let next_pos s = pos (next_token s)
 

+ 14 - 8
src/typing/calls.ml

@@ -60,7 +60,8 @@ let make_call ctx e params t ?(force_inline=false) p =
 		(match cl, ctx.curclass.cl_kind, params with
 			| Some c, KAbstractImpl _, { eexpr = TLocal { v_meta = v_meta } } :: _ when c == ctx.curclass ->
 				if
-					has_meta Meta.This v_meta
+					f.cf_name <> "_new"
+					&& has_meta Meta.This v_meta
 					&& not (assign_to_this_is_allowed ctx)
 					&& has_class_field_flag f CfModifiesThis
 				then
@@ -537,11 +538,14 @@ let rec acc_get ctx g p =
 	| AKMacro _ ->
 		assert false
 
-let rec build_call ctx acc el (with_type:WithType.t) p =
+let rec build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p =
+	let check_assign () = if mode = MSet then invalid_assign p in
 	match acc with
 	| AKInline (ethis,f,fmode,t) when Meta.has Meta.Generic f.cf_meta ->
+		check_assign();
 		type_generic_function ctx (ethis,fmode) el with_type p
 	| AKInline (ethis,f,fmode,t) ->
+		check_assign();
 		(match follow t with
 			| TFun (args,r) ->
 				let _,_,mk_call = unify_field_call ctx fmode el args r p true in
@@ -550,6 +554,7 @@ let rec build_call ctx acc el (with_type:WithType.t) p =
 				error (s_type (print_context()) t ^ " cannot be called") p
 		)
 	| AKUsing (et,cl,ef,eparam,forced_inline (* TOOD? *)) when Meta.has Meta.Generic ef.cf_meta ->
+		check_assign();
 		(match et.eexpr with
 		| TField(ec,fa) ->
 			type_generic_function ctx (ec,fa) el ~using_param:(Some eparam) with_type p
@@ -559,10 +564,11 @@ let rec build_call ctx acc el (with_type:WithType.t) p =
 		| Method MethMacro ->
 			let ethis = type_module_type ctx (TClassDecl cl) None p in
 			let eparam,f = push_this ctx eparam in
-			let e = build_call ctx (AKMacro (ethis,ef)) (eparam :: el) with_type p in
+			let e = build_call ~mode ctx (AKMacro (ethis,ef)) (eparam :: el) with_type p in
 			f();
 			e
 		| _ ->
+			check_assign();
 			let t = follow (field_type ctx cl [] ef p) in
 			(* for abstracts we have to apply their parameters to the static function *)
 			let t,tthis = match follow eparam.etype with
@@ -589,11 +595,11 @@ let rec build_call ctx acc el (with_type:WithType.t) p =
 		let f = (match ethis.eexpr with
 		| TTypeExpr (TClassDecl c) ->
 			(match ctx.g.do_macro ctx MExpr c.cl_path cf.cf_name el p with
-			| None -> (fun() -> type_expr ctx (EConst (Ident "null"),p) WithType.value)
+			| None -> (fun() -> type_expr ~mode ctx (EConst (Ident "null"),p) WithType.value)
 			| Some (EMeta((Meta.MergeBlock,_,_),(EBlock el,_)),_) -> (fun () -> let e = (!type_block_ref) ctx el with_type p in mk (TMeta((Meta.MergeBlock,[],p), e)) e.etype e.epos)
-			| Some e -> (fun() -> type_expr ctx e with_type))
+			| Some e -> (fun() -> type_expr ~mode ctx e with_type))
 		| _ ->
-			(* member-macro call : since we will make a static call, let's found the actual class and not its subclass *)
+			(* member-macro call : since we will make a static call, let's find the actual class and not its subclass *)
 			(match follow ethis.etype with
 			| TInst (c,_) ->
 				let rec loop c =
@@ -601,8 +607,8 @@ let rec build_call ctx acc el (with_type:WithType.t) p =
 						let eparam,f = push_this ctx ethis in
 						ethis_f := f;
 						let e = match ctx.g.do_macro ctx MExpr c.cl_path cf.cf_name (eparam :: el) p with
-							| None -> (fun() -> type_expr ctx (EConst (Ident "null"),p) WithType.value)
-							| Some e -> (fun() -> type_expr ctx e WithType.value)
+							| None -> (fun() -> type_expr ~mode ctx (EConst (Ident "null"),p) WithType.value)
+							| Some e -> (fun() -> type_expr ~mode ctx e WithType.value)
 						in
 						e
 					else

+ 38 - 14
src/typing/fields.ml

@@ -136,7 +136,29 @@ let check_constructor_access ctx c f p =
 	if (Meta.has Meta.CompilerGenerated f.cf_meta) then display_error ctx (error_msg (No_constructor (TClassDecl c))) p;
 	if not (can_access ctx c f true || is_parent c ctx.curclass) && not ctx.untyped then display_error ctx (Printf.sprintf "Cannot access private constructor of %s" (s_class_path c)) p
 
+let check_no_closure_meta ctx fa mode p =
+	if mode <> MCall && not (DisplayPosition.display_position#enclosed_in p) then begin
+		let check_field f cl_meta =
+			match f.cf_kind with
+			| Method _ ->
+				if
+					Meta.has Meta.NoClosure cl_meta
+					|| Meta.has Meta.NoClosure f.cf_meta
+				then
+					error ("Method " ^ f.cf_name ^ " cannot be used as a value") p
+			| _ -> ()
+		in
+		match fa with
+		| FStatic (c, ({ cf_kind = Method _} as f)) -> check_field f c.cl_meta
+		| FInstance (c, _, ({ cf_kind = Method _} as f)) -> check_field f c.cl_meta
+		| FClosure (Some (c, _), ({ cf_kind = Method _} as f)) -> check_field f c.cl_meta
+		| FClosure (None, ({ cf_kind = Method _} as f)) -> check_field f []
+		| FAnon ({ cf_kind = Method _} as f) -> check_field f []
+		| _ -> ()
+	end
+
 let field_access ctx mode f fmode t e p =
+	check_no_closure_meta ctx fmode mode p;
 	let bypass_accessor = if ctx.bypass_accessor > 0 then (ctx.bypass_accessor <- ctx.bypass_accessor - 1; true) else false in
 	let fnormal() = AKExpr (mk (TField (e,fmode)) t p) in
 	let normal() =
@@ -330,6 +352,7 @@ let rec using_field ctx mode e i p =
 
 (* Resolves field [i] on typed expression [e] using the given [mode]. *)
 let rec type_field cfg ctx e i p mode =
+	let pfield = if (e.epos = p) then p else {p with pmin = p.pmax - (String.length i)} in
 	let no_field() =
 		if TypeFieldConfig.do_resume cfg then raise Not_found;
 		let t = match follow e.etype with
@@ -348,9 +371,9 @@ let rec type_field cfg ctx e i p mode =
 			match t with
 			| TAbstract(a,_) when has_special_field a ->
 				(* the abstract field is not part of the field list, which is only true when it has no expression (issue #2344) *)
-				display_error ctx ("Field " ^ i ^ " cannot be called directly because it has no expression") p;
+				display_error ctx ("Field " ^ i ^ " cannot be called directly because it has no expression") pfield;
 			| _ ->
-				display_error ctx (StringError.string_error i (string_source t) (s_type (print_context()) t ^ " has no field " ^ i)) p;
+				display_error ctx (StringError.string_error i (string_source t) (s_type (print_context()) t ^ " has no field " ^ i)) pfield;
 		end;
 		AKExpr (mk (TField (e,FDynamic i)) (mk_mono()) p)
 	in
@@ -402,7 +425,7 @@ let rec type_field cfg ctx e i p mode =
 				| MCall,Var {v_read = AccCall } ->
 					()
 				| MCall, Var _ ->
-					display_error ctx "Cannot access superclass variable for calling: needs to be a proper method" p
+					display_error ctx "Cannot access superclass variable for calling: needs to be a proper method" pfield
 				| MCall, _ ->
 					()
 				| MGet,Var _
@@ -411,8 +434,8 @@ let rec type_field cfg ctx e i p mode =
 				| _, Method _ ->
 					display_error ctx "Cannot create closure on super method" p
 				| _ ->
-					display_error ctx "Normal variables cannot be accessed with 'super', use 'this' instead" p);
-			if not (can_access ctx c f false) && not ctx.untyped then display_error ctx ("Cannot access private field " ^ i) p;
+					display_error ctx "Normal variables cannot be accessed with 'super', use 'this' instead" pfield);
+			if not (can_access ctx c f false) && not ctx.untyped then display_error ctx ("Cannot access private field " ^ i) pfield;
 			field_access ctx mode f (match c2 with None -> FAnon f | Some (c,tl) -> FInstance (c,tl,f)) (apply_params c.cl_params params t) e p
 		with Not_found -> try
 			begin match e.eexpr with
@@ -442,7 +465,7 @@ let rec type_field cfg ctx e i p mode =
 					raise Not_found
 			end
 		with Not_found ->
-			if PMap.mem i c.cl_statics then error ("Cannot access static field " ^ i ^ " from a class instance") p;
+			if PMap.mem i c.cl_statics then error ("Cannot access static field " ^ i ^ " from a class instance") pfield;
 			no_field())
 	| TDynamic t ->
 		(try
@@ -452,12 +475,12 @@ let rec type_field cfg ctx e i p mode =
 	| TAnon a ->
 		(try
 			let f = PMap.find i a.a_fields in
-			if Meta.has Meta.Impl f.cf_meta && not (Meta.has Meta.Enum f.cf_meta) then display_error ctx "Cannot access non-static abstract field statically" p;
+			if Meta.has Meta.Impl f.cf_meta && not (Meta.has Meta.Enum f.cf_meta) then display_error ctx "Cannot access non-static abstract field statically" pfield;
 			if not (has_class_field_flag f CfPublic) && not ctx.untyped then begin
 				match !(a.a_status) with
 				| Closed | Extend _ -> () (* always allow anon private fields access *)
 				| Statics c when can_access ctx c f true -> ()
-				| _ -> display_error ctx ("Cannot access private field " ^ i) p
+				| _ -> display_error ctx ("Cannot access private field " ^ i) pfield
 			end;
 			let fmode, ft = (match !(a.a_status) with
 				| Statics c -> FStatic (c,f), field_type ctx c [] f p
@@ -510,7 +533,7 @@ let rec type_field cfg ctx e i p mode =
 		(try
 			let c = (match a.a_impl with None -> raise Not_found | Some c -> c) in
 			let f = PMap.find i c.cl_statics in
-			if not (can_access ctx c f true) && not ctx.untyped then display_error ctx ("Cannot access private field " ^ i) p;
+			if not (can_access ctx c f true) && not ctx.untyped then display_error ctx ("Cannot access private field " ^ i) pfield;
 			let field_type f =
 				if not (Meta.has Meta.Impl f.cf_meta) then begin
 					static_abstract_access_through_instance := true;
@@ -538,7 +561,7 @@ let rec type_field cfg ctx e i p mode =
 				AKNo f.cf_name
 			| (MGet | MCall), _ ->
 				let rec loop cfl = match cfl with
-					| [] -> error (Printf.sprintf "Field %s cannot be called on %s" f.cf_name (s_type (print_context()) e.etype)) p
+					| [] -> error (Printf.sprintf "Field %s cannot be called on %s" f.cf_name (s_type (print_context()) e.etype)) pfield
 					| cf :: cfl ->
 						match follow (apply_params a.a_params pl (monomorphs cf.cf_params cf.cf_type)) with
 							| TFun((_,_,t1) :: _,_) when type_iseq t1 (Abstract.get_underlying_type a pl) ->
@@ -553,7 +576,7 @@ let rec type_field cfg ctx e i p mode =
 				let t = field_type f in
 				begin match follow t with
 					| TFun((_,_,t1) :: _,_) -> ()
-					| _ -> error ("Invalid call to static function " ^ i ^ " through abstract instance") p
+					| _ -> error ("Invalid call to static function " ^ i ^ " through abstract instance") pfield
 				end;
 				let ef = field_expr f t in
 				AKUsing (ef,c,f,e,false)
@@ -561,7 +584,8 @@ let rec type_field cfg ctx e i p mode =
 				error "This operation is unsupported" p)
 		with Not_found -> try
 			if does_forward a false then
-				type_field (TypeFieldConfig.with_resume cfg) ctx {e with etype = apply_params a.a_params pl a.a_this} i p mode
+				let underlying_type = Abstract.get_underlying_type ~return_first:true a pl in
+				type_field (TypeFieldConfig.with_resume cfg) ctx {e with etype = underlying_type} i p mode
 			else
 				raise Not_found
 		with Not_found -> try
@@ -591,9 +615,9 @@ let rec type_field cfg ctx e i p mode =
 			if not (TypeFieldConfig.allow_resolve cfg) then raise Not_found;
 			get_resolve (mode = MSet)
 		with Not_found ->
-			if !static_abstract_access_through_instance then error ("Invalid call to static function " ^ i ^ " through abstract instance") p
+			if !static_abstract_access_through_instance then error ("Invalid call to static function " ^ i ^ " through abstract instance") pfield
 			else no_field())
 	| _ ->
 		try using_field ctx mode e i p with Not_found -> no_field()
 
-let type_field_default_cfg = type_field TypeFieldConfig.default
+let type_field_default_cfg = type_field TypeFieldConfig.default

+ 6 - 1
src/typing/forLoop.ml

@@ -440,7 +440,12 @@ let type_for_loop ctx handle_display it e2 p =
 			end
 		| EDisplay(e1,dk) -> loop (Some dk) e1
 		| EBinop(OpArrow,ei1,(EBinop(OpIn,ei2,e2),_)) -> IKKeyValue(loop_ident None ei1,loop_ident None ei2),e2
-		| _ -> error "For expression should be 'v in expr'" (snd it)
+		| _ ->
+			begin match dko with
+			| Some dk -> ignore(handle_display ctx e1 dk WithType.value);
+			| None -> ()
+			end;
+			error "For expression should be 'v in expr'" (snd it)
 	in
 	let ik,e1 = loop None it in
 	let e1 = type_expr ctx e1 WithType.value in

+ 2 - 2
src/typing/macroContext.ml

@@ -197,13 +197,13 @@ let make_macro_api ctx p =
 			)
 		);
 		MacroApi.on_type_not_found = (fun f ->
-			ctx.com.load_extern_type <- ctx.com.load_extern_type @ [fun path p ->
+			ctx.com.load_extern_type <- ctx.com.load_extern_type @ ["onTypeNotFound",fun path p ->
 				let td = f (s_type_path path) in
 				if td = Interp.vnull then
 					None
 				else
 					let (pack,name),tdef,p = Interp.decode_type_def td in
-					Some (name,(pack,[tdef,p]))
+					Some (pack,[tdef,p])
 			];
 		);
 		MacroApi.parse_string = parse_expr_string;

+ 11 - 14
src/typing/matcher.ml

@@ -39,7 +39,7 @@ let make_offset_list left right middle other =
 	(ExtList.List.make left other) @ [middle] @ (ExtList.List.make right other)
 
 let type_field_access ctx ?(resume=false) e name =
-	Calls.acc_get ctx (Fields.type_field (Fields.TypeFieldConfig.create resume) ctx e name e.epos TyperBase.MGet) e.epos
+	Calls.acc_get ctx (Fields.type_field (Fields.TypeFieldConfig.create resume) ctx e name e.epos MGet) e.epos
 
 let unapply_type_parameters params monos =
 	List.iter2 (fun (_,t1) t2 -> match t2,follow t2 with TMono m1,TMono m2 when m1 == m2 -> Type.unify t1 t2 | _ -> ()) params monos
@@ -238,15 +238,7 @@ module Pattern = struct
 					PatConstructor(con_type_expr mt e.epos,[])
 				| _ ->
 					let pat = check_expr e in
-					begin try
-						Type.unify e.etype t
-					with (Unify_error l) ->
-						(* Hack: Allow matching the underlying type against its abstract. *)
-						begin match follow e.etype with
-							| TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) && type_iseq t (Abstract.get_underlying_type a tl) -> ()
-							| _ -> raise_or_display ctx l p
-						end
-					end;
+					unify ctx e.etype t p;
 					pat
 		in
 		let handle_ident s p =
@@ -1549,9 +1541,13 @@ module Match = struct
 			| None -> cases
 			| Some (eo,p) -> cases @ [[EConst (Ident "_"),p],None,eo,p]
 		in
-		let tmono,with_type = match with_type with
-			| WithType.WithType(t,_) -> (match follow t with TMono _ -> Some t,WithType.value | _ -> None,with_type)
-			| _ -> None,with_type
+		let tmono,with_type,allow_min_void = match with_type with
+			| WithType.WithType(t,src) ->
+				(match follow t, src with
+				| TMono _, Some ImplicitReturn -> Some t, WithType.Value src, true
+				| TMono _, _ -> Some t,WithType.value,false
+				| _ -> None,with_type,false)
+			| _ -> None,with_type,false
 		in
 		let cases = List.map (fun (el,eg,eo,p) ->
 			let p = match eo with Some e when p = null_pos -> pos e | _ -> p in
@@ -1580,7 +1576,8 @@ module Match = struct
 								(* If we have no block we have to use the `case pattern` position because that's all we have. *)
 								mk (TBlock []) ctx.t.tvoid case.Case.case_pos
 						) cases in
-						unify_min ctx el
+						if allow_min_void then unify_min_for_type_source ctx el (Some WithType.ImplicitReturn)
+						else unify_min ctx el
 					end
 				| WithType.WithType(t,_) -> t
 		in

+ 26 - 16
src/typing/nullSafety.ml

@@ -947,22 +947,32 @@ class expr_checker mode immediate_execution report =
 			E.g.: `Array<Null<String>>` vs `Array<String>` returns `true`, but also adds a compilation error.
 		*)
 		method can_pass_expr expr to_type p =
-			if self#is_nullable_expr expr && not (is_nullable_type to_type) then
-				false
-			else begin
-				let expr_type = unfold_null expr.etype in
-				try
-					new unificator#unify expr_type to_type;
-					true
-				with
-					| Safety_error err ->
-						self#error ("Cannot unify " ^ (str_type expr_type) ^ " with " ^ (str_type to_type)) [p; expr.epos];
-						(* returning `true` because error is already logged in the line above *)
-						true
-					| e ->
-						fail ~msg:"Null safety unification failure" expr.epos __POS__
-				(* can_pass_type expr.etype to_type *)
-			end
+			match expr.eexpr, to_type with
+				| TObjectDecl fields, TAnon to_type ->
+					List.for_all
+						(fun ((name, _, _), field_expr) ->
+							try
+								let field_to_type = PMap.find name to_type.a_fields in
+								self#can_pass_expr field_expr field_to_type.cf_type p
+							with Not_found -> false)
+						fields
+				| _, _ ->
+					if self#is_nullable_expr expr && not (is_nullable_type to_type) then
+						false
+					else begin
+						let expr_type = unfold_null expr.etype in
+						try
+							new unificator#unify expr_type to_type;
+							true
+						with
+							| Safety_error err ->
+								self#error ("Cannot unify " ^ (str_type expr_type) ^ " with " ^ (str_type to_type)) [p; expr.epos];
+								(* returning `true` because error is already logged in the line above *)
+								true
+							| e ->
+								fail ~msg:"Null safety unification failure" expr.epos __POS__
+						(* can_pass_type expr.etype to_type *)
+					end
 		(**
 			Should be called for the root expressions of a method or for then initialization expressions of fields.
 		*)

+ 10 - 11
src/typing/typeload.ml

@@ -254,7 +254,7 @@ let rec load_instance' ctx (t,p) allow_no_params =
 							| _,[EConst(String s),_],_ -> s
 							| _ -> "This typedef is deprecated in favor of " ^ (s_type (print_context()) td.t_type)
 						in
-						ctx.com.warning msg p
+						DeprecationCheck.warn_deprecation ctx.com msg p
 					with Not_found ->
 						()
 					end;
@@ -355,7 +355,7 @@ and load_instance ctx ?(allow_display=false) (t,pn) allow_no_params =
 		t
 	with Error (Module_not_found path,_) when (ctx.com.display.dms_kind = DMDefault) && DisplayPosition.display_position#enclosed_in pn ->
 		let s = s_type_path path in
-		raise_fields (DisplayToplevel.collect ctx TKType NoValue) CRTypeHint (Some {pn with pmin = pn.pmax - String.length s;});
+		DisplayToplevel.collect_and_raise ctx TKType NoValue CRTypeHint (s,pn) (Some {pn with pmin = pn.pmax - String.length s;})
 
 (*
 	build an instance from a complex type
@@ -370,12 +370,12 @@ and load_complex_type' ctx allow_display (t,p) =
 		let tl = List.map (fun (t,pn) ->
 			try
 				load_complex_type ctx allow_display (t,pn)
-			with DisplayException(DisplayFields Some(l,CRTypeHint,p)) ->
+			with DisplayException(DisplayFields Some({fkind = CRTypeHint} as r)) ->
 				let l = List.filter (fun item -> match item.ci_kind with
 					| ITType({kind = Struct},_) -> true
 					| _ -> false
-				) l in
-				raise_fields l (CRStructExtension true) p
+				) r.fitems in
+				raise_fields l (CRStructExtension true) r.finsert_pos
 		) tl in
 		let tr = ref None in
 		let t = TMono tr in
@@ -412,12 +412,12 @@ and load_complex_type' ctx allow_display (t,p) =
 			let il = List.map (fun (t,pn) ->
 				try
 					load_instance ctx ~allow_display (t,pn) false
-				with DisplayException(DisplayFields Some(l,CRTypeHint,p)) ->
+				with DisplayException(DisplayFields Some({fkind = CRTypeHint} as r)) ->
 					let l = List.filter (fun item -> match item.ci_kind with
 						| ITType({kind = Struct},_) -> true
 						| _ -> false
-					) l in
-					raise_fields l (CRStructExtension false) p
+					) r.fitems in
+					raise_fields l (CRStructExtension false) r.finsert_pos
 			) tl in
 			let tr = ref None in
 			let t = TMono tr in
@@ -845,9 +845,8 @@ let handle_path_display ctx path p =
 		DisplayEmitter.display_field ctx origin CFSStatic cf p
 	in
 	match ImportHandling.convert_import_to_something_usable DisplayPosition.display_position#get path,ctx.com.display.dms_kind with
-		| (IDKPackage [_],p),DMDefault ->
-			let fields = DisplayToplevel.collect ctx TKType WithType.no_value in
-			raise_fields fields CRImport (Some p)
+		| (IDKPackage [s],p),DMDefault ->
+			DisplayToplevel.collect_and_raise ctx TKType WithType.no_value CRImport (s,p) (Some p)
 		| (IDKPackage sl,p),DMDefault ->
 			let sl = match List.rev sl with
 				| s :: sl -> List.rev sl

+ 34 - 4
src/typing/typeloadCheck.ml

@@ -130,6 +130,35 @@ let copy_meta meta_src meta_target sl =
 	) meta_src;
 	!meta
 
+(** retrieve string from @:native metadata or raise Not_found *)
+let get_native_name meta =
+	let rec get_native meta = match meta with
+		| [] -> raise Not_found
+		| (Meta.Native,[v],p as meta) :: _ ->
+			meta
+		| _ :: meta ->
+			get_native meta
+	in
+	let (_,e,mp) = get_native meta in
+	match e with
+	| [Ast.EConst (Ast.String name),p] ->
+		name,p
+	| [] ->
+		raise Not_found
+	| _ ->
+		error "String expected" mp
+
+let check_native_name_override ctx child base =
+	let error() =
+		display_error ctx ("Field " ^ child.cf_name ^ " has different @:native value than in superclass") child.cf_pos;
+		display_error ctx ("Base field is defined here") base.cf_pos
+	in
+	try
+		let native_name = fst (get_native_name child.cf_meta) in
+		try if fst (get_native_name base.cf_meta) <> native_name then error()
+		with Not_found -> error()
+	with Not_found -> ()
+
 let check_overriding ctx c f =
 	match c.cl_super with
 	| None ->
@@ -142,6 +171,7 @@ let check_overriding ctx c f =
 			(if is_overload && not (Meta.has Meta.Overload f.cf_meta) then
 				display_error ctx ("Missing @:overload declaration for field " ^ i) p);
 			let t, f2 = get_super_field csup i in
+			check_native_name_override ctx f f2;
 			(* allow to define fields that are not defined for this platform version in superclass *)
 			(match f2.cf_kind with
 			| Var { v_read = AccRequire _ } -> raise Not_found;
@@ -471,9 +501,9 @@ module Inheritance = struct
 			try
 				let t = try
 					Typeload.load_instance ~allow_display:true ctx (ct,p) false
-				with DisplayException(DisplayFields Some(l,CRTypeHint,p)) ->
+				with DisplayException(DisplayFields Some({fkind = CRTypeHint} as r)) ->
 					(* We don't allow `implements` on interfaces. Just raise fields completion with no fields. *)
-					if not is_extends && c.cl_interface then raise_fields [] CRImplements p;
+					if not is_extends && c.cl_interface then raise_fields [] CRImplements r.finsert_pos;
 					let l = List.filter (fun item -> match item.ci_kind with
 						| ITType({kind = Interface} as cm,_) -> (not is_extends || c.cl_interface) && CompletionModuleType.get_path cm <> c.cl_path
 						| ITType({kind = Class} as cm,_) ->
@@ -481,8 +511,8 @@ module Inheritance = struct
 							(not cm.is_final || Meta.has Meta.Hack c.cl_meta) &&
 							(not (is_basic_class_path (cm.pack,cm.name)) || (c.cl_extern && cm.is_extern))
 						| _ -> false
-					) l in
-					raise_fields l (if is_extends then CRExtends else CRImplements) p
+					) r.fitems in
+					raise_fields l (if is_extends then CRExtends else CRImplements) r.finsert_pos
 				in
 				Some (check_herit t is_extends p)
 			with Error(Module_not_found(([],name)),p) when ctx.com.display.dms_kind <> DMNone ->

+ 10 - 6
src/typing/typeloadFields.ml

@@ -217,6 +217,10 @@ let transform_abstract_field com this_t a_t a f =
 			if fu.f_expr <> None then error "MultiType constructors cannot have a body" f.cff_pos;
 			f.cff_access <- (AExtern,null_pos) :: f.cff_access;
 		end;
+		(try
+			let _, p = List.find (fun (acc, _) -> acc = AMacro) f.cff_access in
+			error "Macro abstract constructors are not supported" p
+		with Not_found -> ());
 		(* We don't want the generated expression positions to shadow the real code. *)
 		let p = { p with pmax = p.pmin } in
 		let fu = {
@@ -856,7 +860,8 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p =
 			let ta = TAbstract(a, List.map (fun _ -> mk_mono()) a.a_params) in
 			let tthis = if fctx.is_abstract_member || Meta.has Meta.To cf.cf_meta then monomorphs a.a_params a.a_this else a.a_this in
 			let allows_no_expr = ref (Meta.has Meta.CoreType a.a_meta) in
-			let rec loop ml = match ml with
+			let rec loop ml =
+				(match ml with
 				| (Meta.From,_,_) :: _ ->
 					let r = exc_protect ctx (fun r ->
 						r := lazy_processing (fun () -> t);
@@ -935,7 +940,6 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p =
 						| _ ->
 							display_error ctx ("First argument of implementation function must be " ^ (s_type (print_context()) tthis)) cf.cf_pos
 					end;
-					loop ml
 				| ((Meta.Resolve,_,_) | (Meta.Op,[EField _,_],_)) :: _ ->
 					let targ = if fctx.is_abstract_member then tthis else ta in
 					let check_fun t1 t2 =
@@ -956,10 +960,10 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p =
 						| _ ->
 							error ("Field type of resolve must be " ^ (s_type (print_context()) targ) ^ " -> String -> T") cf.cf_pos
 					end;
-				| _ :: ml ->
-					loop ml
-				| [] ->
-					()
+				| _ -> ());
+				match ml with
+				| _ :: ml -> loop ml
+				| [] -> ()
 			in
 			loop cf.cf_meta;
 			let check_bind () =

+ 1 - 8
src/typing/typeloadFunction.ml

@@ -128,14 +128,7 @@ let type_function ctx args ret fmode f do_display p =
 		if is_display_debug then print_endline ("before processing:\n" ^ (Expr.dump_with_pos e));
 		let e = if !Parser.had_resume then e else Display.ExprPreprocessing.process_expr ctx.com e in
 		if is_display_debug then print_endline ("after processing:\n" ^ (Expr.dump_with_pos e));
-		try
-			if Common.defined ctx.com Define.NoCOpt || not !Parser.had_resume then raise Exit;
-			let e = Optimizer.optimize_completion_expr e f.f_args in
-			if is_display_debug then print_endline ("after optimizing:\n" ^ (Expr.dump_with_pos e));
-			type_expr ctx e NoValue
-		with
-		| Parser.TypePath (_,None,_,_) | Exit ->
-			type_expr ctx e NoValue
+		type_expr ctx e NoValue
 	end in
 	let e = match e.eexpr with
 		| TMeta((Meta.MergeBlock,_,_), ({eexpr = TBlock el} as e1)) -> e1

+ 11 - 5
src/typing/typeloadModule.ml

@@ -771,10 +771,16 @@ let init_module_type ctx context_init do_init (decl,p) =
 				if Meta.has Meta.CoreType a.a_meta then error "@:coreType abstracts cannot have an underlying type" p;
 				let at = load_complex_type ctx true t in
 				delay ctx PForce (fun () ->
-					begin match follow at with
-						| TAbstract(a2,_) when a == a2 -> error "Abstract underlying type cannot be recursive" a.a_pos
+					let rec loop stack t =
+						match follow t with
+						| TAbstract(a,_) when not (Meta.has Meta.CoreType a.a_meta) ->
+							if List.memq a stack then
+								error "Abstract underlying type cannot be recursive" a.a_pos
+							else
+								loop (a :: stack) a.a_this
 						| _ -> ()
-					end;
+					in
+					loop [] at
 				);
 				a.a_this <- at;
 				is_type := true;
@@ -958,10 +964,10 @@ let load_module ctx m p =
 				let rec loop = function
 					| [] ->
 						raise (Error (Module_not_found m,p))
-					| load :: l ->
+					| (file,load) :: l ->
 						match load m p with
 						| None -> loop l
-						| Some (file,(_,a)) -> file, a
+						| Some (_,a) -> file, a
 				in
 				is_extern := true;
 				loop ctx.com.load_extern_type

+ 7 - 3
src/typing/typeloadParse.ml

@@ -144,9 +144,7 @@ let resolve_module_file com m remap p =
 	let timer = Timer.timer ["typing";"resolve_module_file"] in
 	Std.finally timer (resolve_module_file com m remap) p *)
 
-let parse_module' com m p =
-	let remap = ref (fst m) in
-	let file = resolve_module_file com m remap p in
+let parse_module_file com file p =
 	let handle_parser_error msg p =
 		let msg = Parser.error_msg msg in
 		match com.display.dms_error_policy with
@@ -166,6 +164,12 @@ let parse_module' com m p =
 			handle_parser_error msg p;
 			data
 	in
+	pack,decls
+
+let parse_module' com m p =
+	let remap = ref (fst m) in
+	let file = resolve_module_file com m remap p in
+	let pack,decls = parse_module_file com file p in
 	file,remap,pack,decls
 
 let parse_module ctx m p =

+ 115 - 57
src/typing/typer.ml

@@ -42,7 +42,7 @@ let check_assign ctx e =
 	| TConst TThis | TTypeExpr _ when ctx.untyped ->
 		()
 	| _ ->
-		error "Invalid assign" e.epos
+		invalid_assign e.epos
 
 type type_class =
 	| KInt
@@ -51,7 +51,8 @@ type type_class =
 	| KUnk
 	| KDyn
 	| KOther
-	| KParam of t
+	| KNumParam of t
+	| KStrParam of t
 	| KAbstract of tabstract * t list
 
 let rec classify t =
@@ -60,8 +61,10 @@ let rec classify t =
 	| TAbstract({a_impl = Some _} as a,tl) -> KAbstract (a,tl)
 	| TAbstract ({ a_path = [],"Int" },[]) -> KInt
 	| TAbstract ({ a_path = [],"Float" },[]) -> KFloat
-	| TAbstract (a,[]) when List.exists (fun t -> match classify t with KInt | KFloat -> true | _ -> false) a.a_to -> KParam t
-	| TInst ({ cl_kind = KTypeParameter ctl },_) when List.exists (fun t -> match classify t with KInt | KFloat -> true | _ -> false) ctl -> KParam t
+	| TAbstract (a,[]) when List.exists (fun t -> match classify t with KInt | KFloat -> true | _ -> false) a.a_to -> KNumParam t
+	| TInst ({ cl_kind = KTypeParameter ctl },_) when List.exists (fun t -> match classify t with KInt | KFloat -> true | _ -> false) ctl -> KNumParam t
+	| TAbstract (a,[]) when List.exists (fun t -> match classify t with KString -> true | _ -> false) a.a_to -> KStrParam t
+	| TInst ({ cl_kind = KTypeParameter ctl },_) when List.exists (fun t -> match classify t with KString -> true | _ -> false) ctl -> KStrParam t
 	| TMono r when !r = None -> KUnk
 	| TDynamic _ -> KDyn
 	| _ -> KOther
@@ -107,7 +110,7 @@ let maybe_type_against_enum ctx f with_type iscall p =
 				| TAbstract (a,pl) when not (Meta.has Meta.CoreType a.a_meta) ->
 					begin match get_abstract_froms a pl with
 						| [t2] ->
-							if (List.exists (fast_eq t) stack) then raise Exit;
+							if (List.exists (fast_eq_anon ~mono_equals_dynamic:true t) stack) then raise Exit;
 							loop (t :: stack) t2
 						| _ -> raise Exit
 					end
@@ -283,6 +286,13 @@ let unify_min ctx el =
 		if not ctx.untyped then display_error ctx (error_msg (Unify l)) p;
 		(List.hd el).etype
 
+let unify_min_for_type_source ctx el src =
+	match src with
+	| Some WithType.ImplicitReturn when List.exists (fun e -> ExtType.is_void (follow e.etype)) el ->
+		ctx.com.basic.tvoid
+	| _ ->
+		unify_min ctx el
+
 let rec type_ident_raise ctx i p mode =
 	match i with
 	| "true" ->
@@ -695,7 +705,7 @@ and type_binop2 ?(abstract_overload_only=false) ctx op (e1 : texpr) (e2 : Ast.ex
 			| KAbstract ({a_impl = Some c},_) when PMap.mem "toString" c.cl_statics ->
 				call_to_string ctx e
 			| KInt | KFloat | KString -> e
-			| KUnk | KDyn | KParam _ | KOther ->
+			| KUnk | KDyn | KNumParam _ | KStrParam _ | KOther ->
 				let std = type_type ctx ([],"Std") e.epos in
 				let acc = acc_get ctx (type_field_default_cfg ctx std "string" e.epos MCall) e.epos in
 				ignore(follow acc.etype);
@@ -749,18 +759,21 @@ and type_binop2 ?(abstract_overload_only=false) ctx op (e1 : texpr) (e2 : Ast.ex
 			let ok1 = unify_int ctx e1 KUnk in
 			let ok2 = unify_int ctx e2 KUnk in
 			if ok1 && ok2 then tint else tfloat
-		| KParam t1, KParam t2 when Type.type_iseq t1 t2 ->
+		| KNumParam t1, KNumParam t2 when Type.type_iseq t1 t2 ->
 			t1
-		| KParam t, KInt | KInt, KParam t ->
+		| KNumParam t, KInt | KInt, KNumParam t ->
 			t
-		| KParam _, KFloat | KFloat, KParam _ | KParam _, KParam _ ->
+		| KNumParam _, KFloat | KFloat, KNumParam _ | KNumParam _, KNumParam _ ->
 			tfloat
-		| KParam t, KUnk ->
+		| KNumParam t, KUnk ->
 			unify ctx e2.etype tfloat e2.epos;
 			tfloat
-		| KUnk, KParam t ->
+		| KUnk, KNumParam t ->
 			unify ctx e1.etype tfloat e1.epos;
 			tfloat
+		| KStrParam _, _
+		| _, KStrParam _ ->
+			tstring
 		| KAbstract _,KFloat ->
 			unify ctx e1.etype tfloat e1.epos;
 			tfloat
@@ -775,8 +788,8 @@ and type_binop2 ?(abstract_overload_only=false) ctx op (e1 : texpr) (e2 : Ast.ex
 			ctx.t.tint
 		| KAbstract _,_
 		| _,KAbstract _
-		| KParam _, _
-		| _, KParam _
+		| KNumParam _, _
+		| _, KNumParam _
 		| KOther, _
 		| _ , KOther ->
 			let pr = print_context() in
@@ -800,13 +813,13 @@ and type_binop2 ?(abstract_overload_only=false) ctx op (e1 : texpr) (e2 : Ast.ex
 		(match classify e1.etype, classify e2.etype with
 		| KFloat, KFloat ->
 			result := tfloat
-		| KParam t1, KParam t2 when Type.type_iseq t1 t2 ->
+		| KNumParam t1, KNumParam t2 when Type.type_iseq t1 t2 ->
 			if op <> OpDiv then result := t1
-		| KParam _, KParam _ ->
+		| KNumParam _, KNumParam _ ->
 			result := tfloat
-		| KParam t, KInt | KInt, KParam t ->
+		| KNumParam t, KInt | KInt, KNumParam t ->
 			if op <> OpDiv then result := t
-		| KParam _, KFloat | KFloat, KParam _ ->
+		| KNumParam _, KFloat | KFloat, KNumParam _ ->
 			result := tfloat
 		| KFloat, k ->
 			ignore(unify_int ctx e2 k);
@@ -853,8 +866,10 @@ and type_binop2 ?(abstract_overload_only=false) ctx op (e1 : texpr) (e2 : Ast.ex
 		| KDyn , KInt | KDyn , KFloat | KDyn , KString -> ()
 		| KInt , KDyn | KFloat , KDyn | KString , KDyn -> ()
 		| KDyn , KDyn -> ()
-		| KParam _ , x when x <> KString && x <> KOther -> ()
-		| x , KParam _ when x <> KString && x <> KOther -> ()
+		| KNumParam _ , (KInt | KFloat | KNumParam _ | KDyn | KUnk ) -> ()
+		| (KInt | KFloat | KDyn | KUnk ), KNumParam _ -> ()
+		| KStrParam _ , (KString | KStrParam _ | KUnk | KDyn) -> ()
+		| (KString | KUnk | KDyn) , KStrParam _ -> ()
 		| KAbstract _,_
 		| _,KAbstract _
 		| KDyn , KUnk
@@ -863,8 +878,10 @@ and type_binop2 ?(abstract_overload_only=false) ctx op (e1 : texpr) (e2 : Ast.ex
 		| KString , KFloat
 		| KInt , KString
 		| KFloat , KString
-		| KParam _ , _
-		| _ , KParam _
+		| KNumParam _ , _
+		| _ , KNumParam _
+		| KStrParam _ , _
+		| _ , KStrParam _
 		| KOther , _
 		| _ , KOther ->
 			let pr = print_context() in
@@ -1031,7 +1048,7 @@ and type_unop ctx op flag e p =
 				if set then check_assign ctx e;
 				(match classify e.etype with
 				| KFloat -> ctx.t.tfloat
-				| KParam t ->
+				| KNumParam t ->
 					unify ctx e.etype ctx.t.tfloat e.epos;
 					t
 				| k ->
@@ -1345,10 +1362,11 @@ and handle_efield ctx e p mode =
 								raise (Error (Module_not_found (List.rev !path,name),p))
 							with
 								Not_found ->
+									let sl = List.map (fun (n,_,_) -> n) (List.rev acc) in
 									(* if there was no module name part, last guess is that we're trying to get package completion *)
 									if ctx.in_display then begin
-										if ctx.com.json_out = None then raise (Parser.TypePath (List.map (fun (n,_,_) -> n) (List.rev acc),None,false,p))
-										else raise_fields (DisplayToplevel.collect ctx TKType WithType.no_value) CRTypeHint (Some p0);
+										if ctx.com.json_out = None then raise (Parser.TypePath (sl,None,false,p))
+										else DisplayToplevel.collect_and_raise ctx TKType WithType.no_value (CRToplevel None) (String.concat "." sl,p0) (Some p0)
 									end;
 									raise e)
 		in
@@ -1431,7 +1449,7 @@ and type_access ctx e p mode =
 		let resume_typing = type_expr ~mode in
 		AKExpr (TyperDisplay.handle_edisplay ~resume_typing ctx e dk WithType.value)
 	| _ ->
-		AKExpr (type_expr ctx (e,p) WithType.value)
+		AKExpr (type_expr ~mode ctx (e,p) WithType.value)
 
 and type_array_access ctx e1 e2 p mode =
 	let e1 = type_expr ctx e1 WithType.value in
@@ -1603,8 +1621,12 @@ and type_object_decl ctx fl with_type p =
 		let rec loop seen t =
 			match follow t with
 			| TAnon a -> ODKWithStructure a
-			| TAbstract (a,pl) as t when not (Meta.has Meta.CoreType a.a_meta) && not (List.exists (fun t' -> fast_eq t t') seen) ->
-				(match List.fold_left (fun acc t' -> match loop (t :: seen) t' with ODKPlain -> acc | t -> t :: acc) [] (get_abstract_froms a pl) with
+			| TAbstract (a,pl) as t
+				when not (Meta.has Meta.CoreType a.a_meta)
+					&& not (List.exists (fun t' -> fast_eq_anon ~mono_equals_dynamic:true t t') seen) ->
+				let froms = get_abstract_froms a pl
+				and fold = fun acc t' -> match loop (t :: seen) t' with ODKPlain -> acc | t -> t :: acc in
+				(match List.fold_left fold [] froms with
 				| [t] -> t
 				| _ -> ODKPlain)
 			| TDynamic t when (follow t != t_dynamic) ->
@@ -1890,7 +1912,8 @@ and type_try ctx e1 catches with_type p =
 	let e1,catches,t = match with_type with
 		| WithType.NoValue -> e1,catches,ctx.t.tvoid
 		| WithType.Value _ -> e1,catches,unify_min ctx el
-		| WithType.WithType(t,_) when (match follow t with TMono _ -> true | _ -> false) -> e1,catches,unify_min ctx el
+		| WithType.WithType(t,src) when (match follow t with TMono _ -> true | t -> ExtType.is_void t) ->
+			e1,catches,unify_min_for_type_source ctx el src
 		| WithType.WithType(t,_) ->
 			let e1 = AbstractCast.cast_or_unify ctx t e1 e1.epos in
 			let catches = List.map (fun (v,e) ->
@@ -2038,7 +2061,7 @@ and type_local_function ctx name inline f with_type p =
 		tf_expr = e;
 	} in
 	let e = mk (TFunction tf) ft p in
-	(match v with
+	match v with
 	| None -> e
 	| Some v ->
 		Typeload.generate_value_meta ctx.com None (fun m -> v.v_meta <- m :: v.v_meta) f.f_args;
@@ -2050,23 +2073,29 @@ and type_local_function ctx name inline f with_type p =
 			| LocalUsage.Use _ | LocalUsage.Assign _ | LocalUsage.Declare _ -> ()
 		in
 		let is_rec = (try local_usage loop e; false with Exit -> true) in
-		let decl = (if is_rec then begin
-			if inline then display_error ctx "Inline function cannot be recursive" e.epos;
-			let el =
+		let exprs =
+			if with_type <> WithType.NoValue && not inline then [mk (TLocal v) v.v_type p]
+			else []
+		in
+		let exprs =
+			if is_rec then begin
+				if inline then display_error ctx "Inline function cannot be recursive" e.epos;
 				(mk (TVar (v,Some (mk (TConst TNull) ft p))) ctx.t.tvoid p) ::
 				(mk (TBinop (OpAssign,mk (TLocal v) ft p,e)) ft p) ::
-				(if with_type = WithType.NoValue then [] else [mk (TLocal v) ft p])
-			in
-			let e = mk (TBlock el) ft p in
-			{e with eexpr = TMeta((Meta.MergeBlock,[],null_pos),e)}
-		end else if inline && not ctx.com.display.dms_display then
-			mk (TBlock []) ctx.t.tvoid p (* do not add variable since it will be inlined *)
-		else
-			mk (TVar (v,Some e)) ctx.t.tvoid p
-		) in
-		if with_type <> WithType.NoValue && not inline then mk (TBlock [decl;mk (TLocal v) v.v_type p]) v.v_type p else decl)
+				exprs
+			end else if inline && not ctx.com.display.dms_display then
+				(mk (TBlock []) ctx.t.tvoid p) :: exprs (* do not add variable since it will be inlined *)
+			else
+				(mk (TVar (v,Some e)) ctx.t.tvoid p) :: exprs
+		in
+		match exprs with
+		| [e] -> e
+		| _ ->
+			let block = mk (TBlock exprs) v.v_type p in
+			mk (TMeta ((Meta.MergeBlock, [], null_pos), block)) v.v_type p
 
 and type_array_decl ctx el with_type p =
+	let allow_array_dynamic = ref false in
 	let tp = (match with_type with
 	| WithType.WithType(t,_) ->
 		let rec loop seen t =
@@ -2074,16 +2103,18 @@ and type_array_decl ctx el with_type p =
 			| TInst ({ cl_path = [],"Array" },[tp]) ->
 				(match follow tp with
 				| TMono _ -> None
-				| _ -> Some tp)
+				| _ as t ->
+					if t == t_dynamic then allow_array_dynamic := true;
+					Some tp)
 			| TAnon _ ->
 				(try
 					Some (get_iterable_param t)
 				with Not_found ->
 					None)
-			| TAbstract (a,pl) as t when not (List.exists (fun t' -> fast_eq t (follow t')) seen) ->
+			| TAbstract (a,pl) as t when not (List.exists (fun t' -> fast_eq_anon ~mono_equals_dynamic:true t (follow t')) seen) ->
 				let types =
 					List.fold_left
-						(fun acc t -> match loop (t :: seen) t with
+						(fun acc t' -> match loop (t :: seen) t' with
 							| None -> acc
 							| Some t -> t :: acc
 						)
@@ -2094,7 +2125,12 @@ and type_array_decl ctx el with_type p =
 				| [t] -> Some t
 				| _ -> None)
 			| t ->
-				if t == t_dynamic then Some t else None)
+				if t == t_dynamic then begin
+					allow_array_dynamic := true;
+					Some t
+				end else
+					None
+			)
 		in
 		loop [] t
 	| _ ->
@@ -2106,7 +2142,9 @@ and type_array_decl ctx el with_type p =
 		let t = try
 			unify_min_raise ctx.com.basic el
 		with Error (Unify l,p) ->
-			if ctx.untyped || ctx.com.display.dms_error_policy = EPIgnore then t_dynamic else begin
+			if !allow_array_dynamic || ctx.untyped || ctx.com.display.dms_error_policy = EPIgnore then
+				t_dynamic
+			else begin
 				display_error ctx "Arrays of mixed types are only allowed if the type is forced to Array<Dynamic>" p;
 				raise (Error (Unify l, p))
 			end
@@ -2151,19 +2189,24 @@ and type_array_comprehension ctx e with_type p =
 		mk (TLocal v) v.v_type p;
 	]) v.v_type p
 
-and type_return ctx e with_type p =
+and type_return ?(implicit=false) ctx e with_type p =
 	match e with
 	| None ->
 		let v = ctx.t.tvoid in
 		unify ctx v ctx.ret p;
 		let expect_void = match with_type with
 			| WithType.WithType(t,_) -> ExtType.is_void (follow t)
+			| WithType.Value (Some ImplicitReturn) -> true
 			| _ -> false
 		in
 		mk (TReturn None) (if expect_void then v else t_dynamic) p
 	| Some e ->
 		try
-			let e = type_expr ctx e (WithType.with_type ctx.ret) in
+			let with_expected_type =
+				if implicit then WithType.of_implicit_return ctx.ret
+				else WithType.with_type ctx.ret
+			in
+			let e = type_expr ctx e with_expected_type in
 			let e = AbstractCast.cast_or_unify ctx ctx.ret e p in
 			begin match follow e.etype with
 			| TAbstract({a_path=[],"Void"},_) ->
@@ -2225,7 +2268,8 @@ and type_if ctx e e1 e2 with_type p =
 		let e1,e2,t = match with_type with
 			| WithType.NoValue -> e1,e2,ctx.t.tvoid
 			| WithType.Value _ -> e1,e2,unify_min ctx [e1; e2]
-			| WithType.WithType(t,_) when (match follow t with TMono _ -> true | _ -> false) -> e1,e2,unify_min ctx [e1; e2]
+			| WithType.WithType(t,src) when (match follow t with TMono _ -> true | t -> ExtType.is_void t) ->
+				e1,e2,unify_min_for_type_source ctx [e1; e2] src
 			| WithType.WithType(t,_) ->
 				let e1 = AbstractCast.cast_or_unify ctx t e1 e1.epos in
 				let e2 = AbstractCast.cast_or_unify ctx t e2 e2.epos in
@@ -2233,11 +2277,11 @@ and type_if ctx e e1 e2 with_type p =
 		in
 		mk (TIf (e,e1,Some e2)) t p)
 
-and type_meta ctx m e1 with_type p =
+and type_meta ?(mode=MGet) ctx m e1 with_type p =
 	if ctx.is_display_file then DisplayEmitter.check_display_metadata ctx [m];
 	let old = ctx.meta in
 	ctx.meta <- m :: ctx.meta;
-	let e () = type_expr ctx e1 with_type in
+	let e () = type_expr ~mode ctx e1 with_type in
 	let e = match m with
 		| (Meta.ToString,_,_) ->
 			let e = e() in
@@ -2296,6 +2340,11 @@ and type_meta ctx m e1 with_type p =
 				display_error ctx "Call or function expected after inline keyword" p;
 				e();
 			end
+		| (Meta.ImplicitReturn,_,_) ->
+			begin match e1 with
+			| (EReturn e, p) -> type_return ~implicit:true ctx e with_type p
+			| _ -> e()
+			end
 		| _ -> e()
 	in
 	ctx.meta <- old;
@@ -2319,10 +2368,10 @@ and type_call_target ctx e with_type inline p =
 		| _ ->
 			e
 
-and type_call ctx e el (with_type:WithType.t) inline p =
+and type_call ?(mode=MGet) ctx e el (with_type:WithType.t) inline p =
 	let def () =
 		let e = type_call_target ctx e with_type inline p in
-		build_call ctx e el with_type p
+		build_call ~mode ctx e el with_type p
 	in
 	match e, el with
 	| (EConst (Ident "trace"),p) , e :: el ->
@@ -2423,7 +2472,15 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
 		Texpr.type_constant ctx.com.basic c p
 	| EBinop (op,e1,e2) ->
 		type_binop ctx op e1 e2 false with_type p
-	| EBlock [] when with_type <> WithType.NoValue ->
+	| EBlock [] when (match with_type with
+			| NoValue -> false
+			(*
+				If expected type is unknown then treat `(...) -> {}` as an empty function
+				(just like `function(...) {}`) instead of returning an object.
+			*)
+			| WithType (t, Some ImplicitReturn) -> not (ExtType.is_mono (follow t))
+			| _ -> true
+		) ->
 		type_expr ctx (EObjectDecl [],p) with_type
 	| EBlock l ->
 		let locals = save_locals ctx in
@@ -2496,7 +2553,7 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
 		let e = type_expr ctx e WithType.value in
 		mk (TThrow e) (mk_mono()) p
 	| ECall (e,el) ->
-		type_call ctx e el with_type false p
+		type_call ~mode ctx e el with_type false p
 	| ENew (t,el) ->
 		type_new ctx t el with_type false p
 	| EUnop (op,flag,e) ->
@@ -2529,7 +2586,7 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
 		let e = AbstractCast.cast_or_unify ctx t e p in
 		if e.etype == t then e else mk (TCast (e,None)) t p
 	| EMeta (m,e1) ->
-		type_meta ctx m e1 with_type p
+		type_meta ~mode ctx m e1 with_type p
 
 (* ---------------------------------------------------------------------- *)
 (* TYPER INITIALIZATION *)
@@ -2668,6 +2725,7 @@ let rec create com =
 
 ;;
 unify_min_ref := unify_min;
+unify_min_for_type_source_ref := unify_min_for_type_source;
 make_call_ref := make_call;
 build_call_ref := build_call;
 type_call_target_ref := type_call_target;

+ 1 - 6
src/typing/typerBase.ml

@@ -4,11 +4,6 @@ open Type
 open Typecore
 open Error
 
-type access_mode =
-	| MGet
-	| MSet
-	| MCall
-
 type access_kind =
 	| AKNo of string
 	| AKExpr of texpr
@@ -208,7 +203,7 @@ let get_abstract_froms a pl =
 		match follow (Type.field_type f) with
 		| TFun ([_,_,v],t) ->
 			(try
-				ignore(type_eq EqStrict t (TAbstract(a,List.map dup pl))); (* unify fields monomorphs *)
+				ignore(type_eq EqStrict t (TAbstract(a,List.map duplicate pl))); (* unify fields monomorphs *)
 				v :: acc
 			with Unify_error _ ->
 				acc)

+ 17 - 11
src/typing/typerDisplay.ml

@@ -140,9 +140,9 @@ let get_expected_type ctx with_type =
 		| None -> None
 		| Some t -> Some (completion_type_of_type ctx t,completion_type_of_type ctx (follow t))
 
-let raise_toplevel ctx dk with_type po p =
+let raise_toplevel ctx dk with_type (subject,psubject) po =
 	let expected_type = get_expected_type ctx with_type in
-	raise_fields (DisplayToplevel.collect ctx (match dk with DKPattern _ -> TKPattern p | _ -> TKExpr p) with_type) (CRToplevel expected_type) po
+	DisplayToplevel.collect_and_raise ctx (match dk with DKPattern _ -> TKPattern psubject | _ -> TKExpr psubject) with_type (CRToplevel expected_type) (subject,psubject) po
 
 let display_dollar_type ctx p make_type =
 	let mono = mk_mono() in
@@ -401,7 +401,11 @@ and display_expr ctx e_ast e dk with_type p =
 				display_fields e1 e2 (String.length s)
 			| _ ->
 				if dk = DKDot then display_fields e_ast e 0
-				else raise_toplevel ctx dk with_type None p
+				else begin
+					let name = try String.concat "." (string_list_of_expr_path_raise e_ast) with Exit -> "" in
+					let name = if name = "null" then "" else name in
+					raise_toplevel ctx dk with_type (name,pos e_ast) None
+				end
 		end
 	| DMDefault | DMNone | DMModuleSymbols _ | DMDiagnostics _ | DMStatistics ->
 		let fields = DisplayFields.collect ctx e_ast e dk with_type p in
@@ -487,15 +491,15 @@ let handle_display ?resume_typing ctx e_ast dk with_type =
 		| Some fn -> fn ctx e_ast with_type
 	with Error (Unknown_ident n,_) when ctx.com.display.dms_kind = DMDefault ->
         if dk = DKDot && ctx.com.json_out = None then raise (Parser.TypePath ([n],None,false,p))
-		else raise_toplevel ctx dk with_type (Some p) p
+		else raise_toplevel ctx dk with_type (n,p) (Some p)
 	| Error ((Type_not_found (path,_) | Module_not_found path),_) as err when ctx.com.display.dms_kind = DMDefault ->
 		if ctx.com.json_out = None then	begin try
 			raise_fields (DisplayFields.get_submodule_fields ctx path) (CRField((make_ci_module path),p,None,None)) None
 		with Not_found ->
 			raise err
 		end else
-			raise_toplevel ctx dk with_type (Some p) p
-	| DisplayException(DisplayFields Some(l,CRTypeHint,p)) when (match fst e_ast with ENew _ -> true | _ -> false) ->
+			raise_toplevel ctx dk with_type (s_type_path path,p) (Some p)
+	| DisplayException(DisplayFields Some({fkind = CRTypeHint} as r)) when (match fst e_ast with ENew _ -> true | _ -> false) ->
 		let timer = Timer.timer ["display";"toplevel";"filter ctors"] in
 		ctx.pass <- PBuildClass;
 		let l = List.filter (fun item ->
@@ -526,7 +530,9 @@ let handle_display ?resume_typing ctx e_ast dk with_type =
 						let mt = ctx.g.do_load_type_def ctx null_pos {tpackage=mt.pack;tname=mt.module_name;tsub=Some mt.name;tparams=[]} in
 						begin match resolve_typedef mt with
 						| TClassDecl c when has_constructor c -> true
-						| TAbstractDecl {a_impl = Some c} -> PMap.mem "_new" c.cl_statics
+						| TAbstractDecl {a_impl = Some c} ->
+							ignore(c.cl_build());
+							PMap.mem "_new" c.cl_statics
 						| _ -> false
 						end
 					with _ ->
@@ -536,9 +542,9 @@ let handle_display ?resume_typing ctx e_ast dk with_type =
 			| ITTypeParameter {cl_kind = KTypeParameter tl} when get_constructible_constraint ctx tl null_pos <> None ->
 				true
 			| _ -> false
-		) l in
+		) r.fitems in
 		timer();
-		raise_fields l CRNew p
+		raise_fields l CRNew r.finsert_pos
 	in
 	let e = match e.eexpr with
 		| TField(e1,FDynamic "bind") when (match follow e1.etype with TFun _ -> true | _ -> false) -> e1
@@ -594,7 +600,7 @@ let handle_edisplay ?resume_typing ctx e dk with_type =
 	| DKPattern outermost,DMDefault ->
 		begin try
 			handle_display ctx e dk with_type
-		with DisplayException(DisplayFields Some(l,CRToplevel _,p)) ->
-			raise_fields l (CRPattern ((get_expected_type ctx with_type),outermost)) p
+		with DisplayException(DisplayFields Some({fkind = CRToplevel _} as r)) ->
+			raise_fields r.fitems (CRPattern ((get_expected_type ctx with_type),outermost)) r.finsert_pos
 		end
 	| _ -> handle_display ctx e dk with_type

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно