From e646e6f182c920694968ba7a28ad01ddfee4519a Mon Sep 17 00:00:00 2001 From: RblSb Date: Sun, 11 Feb 2024 11:41:45 +0300 Subject: [PATCH 01/49] [ci] Build macOS universal binaries (#11572) * start messing * upd * Build universal binary before testing * separate job * Update macos ocaml version, fix warnings --- .github/workflows/main.yml | 106 +++++++++++++++++------- extra/github-actions/build-mac.yml | 24 ++++-- extra/github-actions/build-windows.yml | 2 +- extra/github-actions/install-nsis.yml | 2 +- extra/github-actions/test-windows.yml | 2 +- extra/github-actions/workflows/main.yml | 76 +++++++++++++---- 6 files changed, 154 insertions(+), 58 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8f005256ba7..04b049d2ee9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,7 +24,7 @@ jobs: rm C:\msys64\usr\bin\bash.exe - name: choco install nsis - uses: nick-invision/retry@v2 + uses: nick-invision/retry@v3 with: timeout_minutes: 10 max_attempts: 10 @@ -114,7 +114,7 @@ jobs: [ $(ls -1 out | wc -l) -eq "3" ] - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: win${{env.ARCH}}Binaries path: out @@ -136,7 +136,7 @@ jobs: - name: Cache opam id: cache-opam - uses: actions/cache@v3.0.11 + uses: actions/cache@v4 with: path: ~/.opam/ key: ${{ runner.os }}-${{ matrix.ocaml }}-${{ hashFiles('./haxe.opam', './libs/') }} @@ -213,13 +213,13 @@ jobs: EOL - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }} path: out - name: Upload xmldoc artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: matrix.ocaml == '4.08.1' with: name: xmldoc @@ -251,7 +251,7 @@ jobs: - uses: actions/checkout@main with: submodules: recursive - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }} path: linuxBinaries @@ -321,13 +321,13 @@ jobs: with: submodules: recursive - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: linuxBinaries path: linuxBinaries - name: Download xmldoc artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: xmldoc path: xmldoc @@ -396,7 +396,7 @@ jobs: FORCE_COLOR: 1 steps: - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -407,7 +407,7 @@ jobs: - name: Set up QEMU id: qemu - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 with: image: tonistiigi/binfmt:latest platforms: all @@ -439,17 +439,23 @@ jobs: EARTHLY_REMOTE_CACHE: "ghcr.io/${{env.CONTAINER_REG}}_cache:build-${{env.CONTAINER_TAG}}-arm64" - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: linuxArm64Binaries path: out/linux/arm64 mac-build: - runs-on: macos-latest + strategy: + fail-fast: false + matrix: + os: [macos-latest, macos-14] + runs-on: ${{ matrix.os }} env: PLATFORM: mac OPAMYES: 1 MACOSX_DEPLOYMENT_TARGET: 10.13 + OCAML_VERSION: 5.1.1 + CTYPES: 0.21.1 steps: - uses: actions/checkout@main with: @@ -457,10 +463,10 @@ jobs: - name: Cache opam id: cache-opam - uses: actions/cache@v3.0.11 + uses: actions/cache@v4 with: path: ~/.opam/ - key: ${{ runner.os }}-${{ hashFiles('./haxe.opam', './libs/') }} + key: ${{ matrix.os }}-${{ hashFiles('./haxe.opam', './libs/') }} - name: Install Neko from S3 run: | @@ -494,16 +500,16 @@ jobs: curl -L https://github.com/madler/zlib/releases/download/v$ZLIB_VERSION/zlib-$ZLIB_VERSION.tar.gz | tar xz cd zlib-$ZLIB_VERSION ./configure - make && make install + sudo make && sudo make install cd .. curl -L https://github.com/ARMmbed/mbedtls/archive/v$MBEDTLS_VERSION.tar.gz | tar xz cd mbedtls-$MBEDTLS_VERSION - make && make install + sudo make && sudo make install cd .. curl -L https://github.com/PCRE2Project/pcre2/releases/download/pcre2-$PCRE2_VERSION/pcre2-$PCRE2_VERSION.tar.gz | tar xz cd pcre2-$PCRE2_VERSION ./configure --enable-unicode --enable-pcre2-8 --enable-pcre2-16 --enable-pcre2-32 --enable-unicode-properties --enable-pcre2grep-libz --enable-pcre2grep-libbz2 --enable-jit - make && make install + sudo make && sudo make install cd .. - name: Install OCaml libraries @@ -512,10 +518,10 @@ jobs: set -ex opam init # --disable-sandboxing opam update - opam switch create 4.08.1 + opam switch create ${{env.OCAML_VERSION}} eval $(opam env) opam env - opam pin add ctypes 0.17.1 --yes + opam pin add ctypes ${{env.CTYPES}} --yes opam pin add haxe . --no-action opam install haxe --deps-only --assume-depexts opam list @@ -536,10 +542,18 @@ jobs: otool -L ./haxe otool -L ./haxelib - - name: Upload artifact - uses: actions/upload-artifact@v3 + - name: Upload artifact (x64) + if: matrix.os == 'macos-latest' + uses: actions/upload-artifact@v4 with: - name: macBinaries + name: macX64Binaries + path: out + + - name: Upload artifact (arm) + if: matrix.os == 'macos-14' + uses: actions/upload-artifact@v4 + with: + name: macArmBinaries path: out @@ -561,7 +575,7 @@ jobs: - uses: actions/checkout@main with: submodules: recursive - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: win${{env.ARCH}}Binaries path: win${{env.ARCH}}Binaries @@ -578,7 +592,7 @@ jobs: - name: Print Neko version run: neko -version 2>&1 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 18.17.1 @@ -639,9 +653,43 @@ jobs: working-directory: ${{github.workspace}}/tests - mac-test: + mac-build-universal: needs: mac-build runs-on: macos-latest + steps: + - name: Checkout the repository + uses: actions/checkout@main + - uses: actions/download-artifact@v4 + with: + name: macX64Binaries + path: macX64Binaries + - uses: actions/download-artifact@v4 + with: + name: macArmBinaries + path: macArmBinaries + + - name: Make universal binary + run: | + set -ex + tar -xf macX64Binaries/*_bin.tar.gz -C macX64Binaries --strip-components=1 + tar -xf macArmBinaries/*_bin.tar.gz -C macArmBinaries --strip-components=1 + lipo -create -output haxe macX64Binaries/haxe macArmBinaries/haxe + # there is only x64 haxelib + mv macX64Binaries/haxelib . + make -s package_unix package_installer_mac + ls -l out + otool -L ./haxe + otool -L ./haxelib + + - name: Upload artifact (universal) + uses: actions/upload-artifact@v4 + with: + name: macBinaries + path: out + + mac-test: + needs: mac-build-universal + runs-on: macos-latest env: PLATFORM: mac TEST: ${{matrix.target}} @@ -658,7 +706,7 @@ jobs: - uses: actions/checkout@main with: submodules: recursive - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: macBinaries path: macBinaries @@ -726,7 +774,7 @@ jobs: uses: actions/checkout@main - name: Download build artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Install awscli run: | @@ -795,7 +843,7 @@ jobs: sudo apt-get install -qqy libc6 - name: Download Haxe - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: linuxBinaries path: linuxBinaries @@ -811,7 +859,7 @@ jobs: sudo ln -s `pwd`/linuxBinaries/std /usr/local/share/haxe/std - name: Download xmldoc artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: xmldoc path: xmldoc diff --git a/extra/github-actions/build-mac.yml b/extra/github-actions/build-mac.yml index 518912aff7a..543d9ba1105 100644 --- a/extra/github-actions/build-mac.yml +++ b/extra/github-actions/build-mac.yml @@ -13,16 +13,16 @@ curl -L https://github.com/madler/zlib/releases/download/v$ZLIB_VERSION/zlib-$ZLIB_VERSION.tar.gz | tar xz cd zlib-$ZLIB_VERSION ./configure - make && make install + sudo make && sudo make install cd .. curl -L https://github.com/ARMmbed/mbedtls/archive/v$MBEDTLS_VERSION.tar.gz | tar xz cd mbedtls-$MBEDTLS_VERSION - make && make install + sudo make && sudo make install cd .. curl -L https://github.com/PCRE2Project/pcre2/releases/download/pcre2-$PCRE2_VERSION/pcre2-$PCRE2_VERSION.tar.gz | tar xz cd pcre2-$PCRE2_VERSION ./configure --enable-unicode --enable-pcre2-8 --enable-pcre2-16 --enable-pcre2-32 --enable-unicode-properties --enable-pcre2grep-libz --enable-pcre2grep-libbz2 --enable-jit - make && make install + sudo make && sudo make install cd .. - name: Install OCaml libraries @@ -31,10 +31,10 @@ set -ex opam init # --disable-sandboxing opam update - opam switch create 4.08.1 + opam switch create ${{env.OCAML_VERSION}} eval $(opam env) opam env - opam pin add ctypes 0.17.1 --yes + opam pin add ctypes ${{env.CTYPES}} --yes opam pin add haxe . --no-action opam install haxe --deps-only --assume-depexts opam list @@ -55,8 +55,16 @@ otool -L ./haxe otool -L ./haxelib -- name: Upload artifact - uses: actions/upload-artifact@v3 +- name: Upload artifact (x64) + if: matrix.os == 'macos-latest' + uses: actions/upload-artifact@v4 with: - name: macBinaries + name: macX64Binaries + path: out + +- name: Upload artifact (arm) + if: matrix.os == 'macos-14' + uses: actions/upload-artifact@v4 + with: + name: macArmBinaries path: out diff --git a/extra/github-actions/build-windows.yml b/extra/github-actions/build-windows.yml index f429e129ee8..2bfa654aa13 100644 --- a/extra/github-actions/build-windows.yml +++ b/extra/github-actions/build-windows.yml @@ -34,7 +34,7 @@ [ $(ls -1 out | wc -l) -eq "3" ] - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: win${{env.ARCH}}Binaries path: out diff --git a/extra/github-actions/install-nsis.yml b/extra/github-actions/install-nsis.yml index 5c77f1c978d..5f84db3d130 100644 --- a/extra/github-actions/install-nsis.yml +++ b/extra/github-actions/install-nsis.yml @@ -1,5 +1,5 @@ - name: choco install nsis - uses: nick-invision/retry@v2 + uses: nick-invision/retry@v3 with: timeout_minutes: 10 max_attempts: 10 diff --git a/extra/github-actions/test-windows.yml b/extra/github-actions/test-windows.yml index 397f2f9a144..96c02751847 100644 --- a/extra/github-actions/test-windows.yml +++ b/extra/github-actions/test-windows.yml @@ -1,4 +1,4 @@ -- uses: actions/setup-node@v3 +- uses: actions/setup-node@v4 with: node-version: 18.17.1 diff --git a/extra/github-actions/workflows/main.yml b/extra/github-actions/workflows/main.yml index 2d6198b37da..1e360f97e8e 100644 --- a/extra/github-actions/workflows/main.yml +++ b/extra/github-actions/workflows/main.yml @@ -44,7 +44,7 @@ jobs: - name: Cache opam id: cache-opam - uses: actions/cache@v3.0.11 + uses: actions/cache@v4 with: path: ~/.opam/ key: ${{ runner.os }}-${{ matrix.ocaml }}-${{ hashFiles('./haxe.opam', './libs/') }} @@ -105,13 +105,13 @@ jobs: EOL - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }} path: out - name: Upload xmldoc artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: matrix.ocaml == '4.08.1' with: name: xmldoc @@ -143,7 +143,7 @@ jobs: - uses: actions/checkout@main with: submodules: recursive - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }} path: linuxBinaries @@ -197,13 +197,13 @@ jobs: with: submodules: recursive - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: linuxBinaries path: linuxBinaries - name: Download xmldoc artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: xmldoc path: xmldoc @@ -256,7 +256,7 @@ jobs: FORCE_COLOR: 1 steps: - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -267,7 +267,7 @@ jobs: - name: Set up QEMU id: qemu - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 with: image: tonistiigi/binfmt:latest platforms: all @@ -299,17 +299,23 @@ jobs: EARTHLY_REMOTE_CACHE: "ghcr.io/${{env.CONTAINER_REG}}_cache:build-${{env.CONTAINER_TAG}}-arm64" - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: linuxArm64Binaries path: out/linux/arm64 mac-build: - runs-on: macos-latest + strategy: + fail-fast: false + matrix: + os: [macos-latest, macos-14] + runs-on: ${{ matrix.os }} env: PLATFORM: mac OPAMYES: 1 MACOSX_DEPLOYMENT_TARGET: 10.13 + OCAML_VERSION: 5.1.1 + CTYPES: 0.21.1 steps: - uses: actions/checkout@main with: @@ -317,10 +323,10 @@ jobs: - name: Cache opam id: cache-opam - uses: actions/cache@v3.0.11 + uses: actions/cache@v4 with: path: ~/.opam/ - key: ${{ runner.os }}-${{ hashFiles('./haxe.opam', './libs/') }} + key: ${{ matrix.os }}-${{ hashFiles('./haxe.opam', './libs/') }} @import install-neko-unix.yml @import build-mac.yml @@ -343,7 +349,7 @@ jobs: - uses: actions/checkout@main with: submodules: recursive - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: win${{env.ARCH}}Binaries path: win${{env.ARCH}}Binaries @@ -351,9 +357,43 @@ jobs: @import install-neko-windows.yml @import test-windows.yml - mac-test: + mac-build-universal: needs: mac-build runs-on: macos-latest + steps: + - name: Checkout the repository + uses: actions/checkout@main + - uses: actions/download-artifact@v4 + with: + name: macX64Binaries + path: macX64Binaries + - uses: actions/download-artifact@v4 + with: + name: macArmBinaries + path: macArmBinaries + + - name: Make universal binary + run: | + set -ex + tar -xf macX64Binaries/*_bin.tar.gz -C macX64Binaries --strip-components=1 + tar -xf macArmBinaries/*_bin.tar.gz -C macArmBinaries --strip-components=1 + lipo -create -output haxe macX64Binaries/haxe macArmBinaries/haxe + # there is only x64 haxelib + mv macX64Binaries/haxelib . + make -s package_unix package_installer_mac + ls -l out + otool -L ./haxe + otool -L ./haxelib + + - name: Upload artifact (universal) + uses: actions/upload-artifact@v4 + with: + name: macBinaries + path: out + + mac-test: + needs: mac-build-universal + runs-on: macos-latest env: PLATFORM: mac TEST: ${{matrix.target}} @@ -370,7 +410,7 @@ jobs: - uses: actions/checkout@main with: submodules: recursive - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: macBinaries path: macBinaries @@ -390,7 +430,7 @@ jobs: uses: actions/checkout@main - name: Download build artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Install awscli run: | @@ -459,7 +499,7 @@ jobs: sudo apt-get install -qqy libc6 - name: Download Haxe - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: linuxBinaries path: linuxBinaries @@ -475,7 +515,7 @@ jobs: sudo ln -s `pwd`/linuxBinaries/std /usr/local/share/haxe/std - name: Download xmldoc artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: xmldoc path: xmldoc From 4aa876b8ca63dadbef9c0711cb9d7d6a91e3b6a6 Mon Sep 17 00:00:00 2001 From: Frixuu Date: Tue, 13 Feb 2024 17:59:49 +0100 Subject: [PATCH 02/49] [lua] Share metatables with other class instances (#11103) * [lua] enable metatable sharing within same class (opt-in) * [lua] actually, make the shared metatable the default * [lua] make lua.Lua.getmetatable accept Any as parameter https://www.lua.org/manual/5.1/manual.html#pdf-getmetatable * [tests] check if Lua target actually shares metatables within class * [lua] revert lua.Lua change --- src/generators/genlua.ml | 14 +++++++++++--- std/lua/_lua/_hx_anon.lua | 4 ---- std/lua/_lua/_hx_objects.lua | 15 +++++++++++++++ std/lua/_lua/_hx_tab_array.lua | 2 +- tests/unit/src/unit/TestLua.hx | 27 +++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 std/lua/_lua/_hx_objects.lua diff --git a/src/generators/genlua.ml b/src/generators/genlua.ml index 176185edbcf..8e07969c724 100644 --- a/src/generators/genlua.ml +++ b/src/generators/genlua.ml @@ -1550,7 +1550,7 @@ let check_multireturn ctx c = let check_field_name c f = match f.cf_name with - | "prototype" | "__proto__" | "constructor" -> + | "prototype" | "__proto__" | "constructor" | "__mt__" -> raise_typing_error ("The field name '" ^ f.cf_name ^ "' is not allowed in Lua") (match f.cf_expr with None -> c.cl_pos | Some e -> e.epos); | _ -> () @@ -1660,8 +1660,10 @@ let generate_class ctx c = | TBlock el -> let bend = open_block ctx in newline ctx; - if not (has_prototype ctx c) then println ctx "local self = _hx_new()" else - println ctx "local self = _hx_new(%s.prototype)" p; + if not (has_prototype ctx c) then + println ctx "local self = _hx_new()" + else + println ctx "local self = _hx_nsh(%s.__mt__)" p; println ctx "%s.super(%s)" p (String.concat "," ("self" :: (List.map lua_arg_name f.tf_args))); if p = "String" then println ctx "self = string"; spr ctx "return self"; @@ -1734,6 +1736,9 @@ let generate_class ctx c = if has_property_reflection && Codegen.has_properties csup then println ctx "setmetatable(%s.prototype.__properties__,{__index=%s.prototype.__properties__})" p psup; ); + + (* Create a metatable specific for this class *) + println ctx "%s.__mt__ = _hx_mmt(%s.prototype)" p p; end let generate_enum ctx e = @@ -2023,6 +2028,9 @@ let generate com = (* base lua metatables for prototypes, inheritance, etc. *) print_file (Common.find_file com "lua/_lua/_hx_anon.lua"); + (* Helpers for creating metatables from prototypes *) + print_file (Common.find_file com "lua/_lua/_hx_objects.lua"); + (* base runtime class stubs for haxe value types (Int, Float, etc) *) print_file (Common.find_file com "lua/_lua/_hx_classes.lua"); diff --git a/std/lua/_lua/_hx_anon.lua b/std/lua/_lua/_hx_anon.lua index 6ffc55b15a9..e628ad7320c 100644 --- a/std/lua/_lua/_hx_anon.lua +++ b/std/lua/_lua/_hx_anon.lua @@ -28,10 +28,6 @@ local function _hx_o(obj) return setmetatable(obj, _hx_obj_mt) end -local function _hx_new(prototype) - return setmetatable({__fields__ = {}}, {__newindex=_hx_obj_newindex, __index=prototype, __tostring=_hx_tostring}) -end - function _hx_field_arr(obj) local res = {} local idx = 0 diff --git a/std/lua/_lua/_hx_objects.lua b/std/lua/_lua/_hx_objects.lua new file mode 100644 index 00000000000..4bc25b953d8 --- /dev/null +++ b/std/lua/_lua/_hx_objects.lua @@ -0,0 +1,15 @@ +local function _hx_mmt(prototype) + return { + __newindex = _hx_obj_newindex, + __index = prototype, + __tostring = _hx_tostring + } +end + +local function _hx_new(prototype) + return setmetatable({ __fields__ = {} }, _hx_mmt(prototype)) +end + +local function _hx_nsh(metatable) + return setmetatable({ __fields__ = {} }, metatable) +end diff --git a/std/lua/_lua/_hx_tab_array.lua b/std/lua/_lua/_hx_tab_array.lua index ec79ff45bab..e3c85db7fcf 100644 --- a/std/lua/_lua/_hx_tab_array.lua +++ b/std/lua/_lua/_hx_tab_array.lua @@ -1,4 +1,4 @@ -local _hx_hidden = {__id__=true, hx__closures=true, super=true, prototype=true, __fields__=true, __ifields__=true, __class__=true, __properties__=true, __fields__=true, __name__=true} +local _hx_hidden = {__id__=true, hx__closures=true, super=true, prototype=true, __fields__=true, __ifields__=true, __class__=true, __properties__=true, __mt__=true, __name__=true} _hx_array_mt = { __newindex = function(t,k,v) diff --git a/tests/unit/src/unit/TestLua.hx b/tests/unit/src/unit/TestLua.hx index dc1ff71270a..69ab587c3fd 100644 --- a/tests/unit/src/unit/TestLua.hx +++ b/tests/unit/src/unit/TestLua.hx @@ -1,5 +1,7 @@ package unit; +import utest.Assert; + class TestLua extends Test { function testMultiReturnWrap(){ var multi : Multi = untyped MultiCall.doit(); @@ -45,6 +47,27 @@ class TestLua extends Test { untyped _hx_box_mr = old_hx_box_mr; } + function testMetatablesAreShared() { + + // New class instances get metatables assigned to them + final a = new TLA(); + t(lua.Lua.getmetatable(cast a) != null); + + // Instances of the same class share a metatable + final a2 = new TLA(); + eq(lua.Lua.getmetatable(cast a), lua.Lua.getmetatable(cast a2)); + + // Subclass does not share a metatable with the parent + final aChild = new TLAChild(); + t(lua.Lua.getmetatable(cast aChild) != null); + Assert.notEquals(lua.Lua.getmetatable(cast a), lua.Lua.getmetatable(cast aChild)); + + // Neither do any other arbitrary two classes + final b = new TLB(); + t(lua.Lua.getmetatable(cast b) != null); + Assert.notEquals(lua.Lua.getmetatable(cast a), lua.Lua.getmetatable(cast b)); + Assert.notEquals(lua.Lua.getmetatable(cast aChild), lua.Lua.getmetatable(cast b)); + } } @:multiReturn extern class Multi { @@ -60,3 +83,7 @@ class MultiCall { return lua.Lua.type(m) == "table"; } } + +class TLA { private var foo: String; public function new() { this.foo = "A"; } } +class TLAChild extends TLA { public function new() { super(); this.foo = "AChild"; } } +class TLB { private var foo: String; public function new() { this.foo = "B"; } } From 1c6fc84dec91aac8b3bb8469ab4b9d88b9136f96 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 14 Feb 2024 06:17:27 +0100 Subject: [PATCH 03/49] pin luv to 0.5.12 for now see #11575 --- haxe.opam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe.opam b/haxe.opam index 6b8d4f8d8f1..0201bb6694c 100644 --- a/haxe.opam +++ b/haxe.opam @@ -31,7 +31,7 @@ depends: [ "conf-libpcre2-8" "conf-zlib" "conf-neko" - "luv" {>= "0.5.12"} + "luv" {= "0.5.12"} "ipaddr" "terminal_size" ] From a57c74c770e986f6bbd40c350af6e1bae65abf0b Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 14 Feb 2024 10:55:08 +0100 Subject: [PATCH 04/49] send increment unops through make_binop see #11577 --- src/typing/operators.ml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/typing/operators.ml b/src/typing/operators.ml index c75663686be..13751dc78db 100644 --- a/src/typing/operators.ml +++ b/src/typing/operators.ml @@ -866,6 +866,10 @@ let type_unop ctx op flag e with_type p = | None -> vr#to_texpr e | Some e' -> vr#to_texpr_el [e] e' in + let make_op vr binop e1 e2 p = + let result = make_binop ctx binop e1 e2 false p in + BinopResult.to_texpr vr result (fun _ -> raise Not_found) + in let rec loop access_set = match access_set with | AKNo(acc,p) -> begin try @@ -887,7 +891,7 @@ let type_unop ctx op flag e with_type p = let e_set = FieldAccess.get_field_expr {fa with fa_on = ef} FWrite in let e_lhs = acc_get ctx access_get in let e_lhs,e_out = maybe_tempvar_postfix vr e_lhs in - let e_op = mk (TBinop(binop,e_lhs,e_one)) e_lhs.etype p in + let e_op = make_op vr binop e_lhs e_one p in mk (TBinop(OpAssign,e_set,e_op)) e_set.etype p,e_out in generate vr e_out e @@ -896,14 +900,14 @@ let type_unop ctx op flag e with_type p = let ef = vr#get_expr_part "fh" fa.fa_on in let fa = {fa with fa_on = ef} in let e_lhs,e_out = read_on vr ef fa in - let e_op = mk (TBinop(binop,e_lhs,e_one)) e_lhs.etype p in + let e_op = make_op vr binop e_lhs e_one p in let dispatcher = new call_dispatcher ctx (MSet None) WithType.value p in let e = dispatcher#accessor_call fa [e_op] [] in generate vr e_out e | AKUsingAccessor sea -> let ef,vr = process_lhs_expr ctx "fh" sea.se_this in let e_lhs,e_out = read_on vr ef sea.se_access in - let e_op = mk (TBinop(binop,e_lhs,e_one)) e_lhs.etype p in + let e_op = make_op vr binop e_lhs e_one p in let dispatcher = new call_dispatcher ctx (MSet None) WithType.value p in let e = dispatcher#accessor_call sea.se_access [ef;e_op] [] in generate vr e_out e From 707ea41d567fd75613b75f0f8973d011085f3be8 Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Thu, 15 Feb 2024 13:51:10 +0100 Subject: [PATCH 05/49] Use VInlinedConstructorVariable to tag inlined but interesting variable for debug (#11578) * Let inlineCtor in a not inline func gives VInlinedConstructorVariable * Let VInlinedConstructorVariable carry original variable info as string * Let get_pretty_name return a list, remove the illusion of having . in v_name * Only tag VInlinedC when needed, was overwriting VGenerated * Replace is_gen_local name, use string list for VInlinedC --- src/compiler/hxb/hxbReader.ml | 2 +- src/compiler/hxb/hxbWriter.ml | 30 ++++++++++++++------------ src/core/tPrinting.ml | 2 +- src/core/tType.ml | 2 +- src/filters/filters.ml | 2 +- src/generators/genhl.ml | 9 +++++--- src/macro/eval/evalJit.ml | 2 +- src/optimization/analyzer.ml | 2 +- src/optimization/analyzerTexpr.ml | 2 +- src/optimization/inlineConstructors.ml | 23 +++++++++++++++----- 10 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/compiler/hxb/hxbReader.ml b/src/compiler/hxb/hxbReader.ml index 74133f9b887..0f5e8074d61 100644 --- a/src/compiler/hxb/hxbReader.ml +++ b/src/compiler/hxb/hxbReader.ml @@ -963,7 +963,7 @@ class hxb_reader | 5 -> VUser TVOLocalFunction | 6 -> VGenerated | 7 -> VInlined - | 8 -> VInlinedConstructorVariable + | 8 -> VInlinedConstructorVariable (self#read_list (fun () -> self#read_string)) | 9 -> VExtractorVariable | 10 -> VAbstractThis | _ -> assert false diff --git a/src/compiler/hxb/hxbWriter.ml b/src/compiler/hxb/hxbWriter.ml index 32b2b1e82fd..15ecb255825 100644 --- a/src/compiler/hxb/hxbWriter.ml +++ b/src/compiler/hxb/hxbWriter.ml @@ -980,20 +980,22 @@ module HxbWriter = struct Chunk.write_uleb128 writer.chunk (Pool.add writer.enum_fields key (en,ef)) let write_var_kind writer vk = - let b = match vk with - | VUser TVOLocalVariable -> 0 - | VUser TVOArgument -> 1 - | VUser TVOForVariable -> 2 - | VUser TVOPatternVariable -> 3 - | VUser TVOCatchVariable -> 4 - | VUser TVOLocalFunction -> 5 - | VGenerated -> 6 - | VInlined -> 7 - | VInlinedConstructorVariable -> 8 - | VExtractorVariable -> 9 - | VAbstractThis -> 10 - in - Chunk.write_u8 writer.chunk b + let b,sl = match vk with + | VUser TVOLocalVariable -> 0, [] + | VUser TVOArgument -> 1, [] + | VUser TVOForVariable -> 2, [] + | VUser TVOPatternVariable -> 3, [] + | VUser TVOCatchVariable -> 4, [] + | VUser TVOLocalFunction -> 5, [] + | VGenerated -> 6, [] + | VInlined -> 7, [] + | VInlinedConstructorVariable sl -> 8, sl + | VExtractorVariable -> 9, [] + | VAbstractThis -> 10, [] + in begin + Chunk.write_u8 writer.chunk b; + if (b == 8) then Chunk.write_list writer.chunk sl (Chunk.write_string writer.chunk); + end let write_var writer fctx v = Chunk.write_uleb128 writer.chunk v.v_id; diff --git a/src/core/tPrinting.ml b/src/core/tPrinting.ml index 954de7e1104..2ce6843485f 100644 --- a/src/core/tPrinting.ml +++ b/src/core/tPrinting.ml @@ -601,7 +601,7 @@ module Printer = struct | TVOLocalFunction -> "TVOLocalFunction") ^ ")" | VGenerated -> "VGenerated" | VInlined -> "VInlined" - | VInlinedConstructorVariable -> "VInlinedConstructorVariable" + | VInlinedConstructorVariable sl -> "VInlinedConstructorVariable" ^ "(" ^ (String.concat ", " sl) ^ ")" | VExtractorVariable -> "VExtractorVariable" | VAbstractThis -> "VAbstractThis" diff --git a/src/core/tType.ml b/src/core/tType.ml index 205d4415e91..876720fc849 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -144,7 +144,7 @@ and tvar_kind = | VUser of tvar_origin | VGenerated | VInlined - | VInlinedConstructorVariable + | VInlinedConstructorVariable of string list | VExtractorVariable | VAbstractThis diff --git a/src/filters/filters.ml b/src/filters/filters.ml index d9a1077fe60..4c12093f5e2 100644 --- a/src/filters/filters.ml +++ b/src/filters/filters.ml @@ -103,7 +103,7 @@ let check_local_vars_init ctx e = | TVar (v,eo) -> begin match eo with - | None when v.v_kind = VInlinedConstructorVariable -> + | None when (match v.v_kind with VInlinedConstructorVariable _ -> true | _ -> false) -> () | None -> declared := v.v_id :: !declared; diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index e3ba1481b68..0c26dd72ed6 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -991,14 +991,17 @@ let real_name v = in match loop v.v_meta with | "_gthis" -> "this" - | name -> name + | name -> match v.v_kind with + | VInlinedConstructorVariable sl -> String.concat "." sl + | _ -> name -let is_gen_local ctx v = match v.v_kind with +let not_debug_var ctx v = match v.v_kind with | VUser _ -> false + | VInlinedConstructorVariable _ -> false | _ -> true let add_assign ctx v = - if is_gen_local ctx v then () else + if not_debug_var ctx v then () else let name = real_name v in ctx.m.massign <- (alloc_string ctx name, current_pos ctx - 1) :: ctx.m.massign diff --git a/src/macro/eval/evalJit.ml b/src/macro/eval/evalJit.ml index 89c428641ce..8d0dbd6c701 100644 --- a/src/macro/eval/evalJit.ml +++ b/src/macro/eval/evalJit.ml @@ -655,7 +655,7 @@ and jit_expr jit return e = wrap() | TUnop((Increment | Decrement),_,e1) | TBinop((OpAssign | OpAssignOp _),e1,_) -> begin match (Texpr.skip e1).eexpr with - | TLocal {v_kind = VGenerated | VInlined | VInlinedConstructorVariable | VExtractorVariable} -> + | TLocal {v_kind = VGenerated | VInlined | VInlinedConstructorVariable _ | VExtractorVariable} -> f | _ -> wrap() diff --git a/src/optimization/analyzer.ml b/src/optimization/analyzer.ml index 1664f0e4698..cb80af4e33a 100644 --- a/src/optimization/analyzer.ml +++ b/src/optimization/analyzer.ml @@ -664,7 +664,7 @@ module LocalDce = struct has_var_flag v VAnalyzed in let keep v = - is_used v || ((match v.v_kind with VUser _ | VInlined -> true | _ -> false) && not ctx.config.local_dce) || ExtType.has_reference_semantics v.v_type || has_var_flag v VCaptured || Meta.has Meta.This v.v_meta + is_used v || ((match v.v_kind with VUser _ | VInlined | VInlinedConstructorVariable _ -> true | _ -> false) && not ctx.config.local_dce) || ExtType.has_reference_semantics v.v_type || has_var_flag v VCaptured || Meta.has Meta.This v.v_meta in let rec use v = if not (is_used v) then begin diff --git a/src/optimization/analyzerTexpr.ml b/src/optimization/analyzerTexpr.ml index 7b09d058d5e..dc9aa066429 100644 --- a/src/optimization/analyzerTexpr.ml +++ b/src/optimization/analyzerTexpr.ml @@ -790,7 +790,7 @@ module Fusion = struct let num_uses = state#get_reads v in let num_writes = state#get_writes v in let can_be_used_as_value = can_be_used_as_value com e in - let is_compiler_generated = match v.v_kind with VUser _ | VInlined -> false | _ -> true in + let is_compiler_generated = match v.v_kind with VUser _ | VInlined | VInlinedConstructorVariable _ -> false | _ -> true in let has_type_params = match v.v_extra with Some ve when ve.v_params <> [] -> true | _ -> false in let rec is_impure_extern e = match e.eexpr with | TField(ef,(FStatic(cl,cf) | FInstance(cl,_,cf))) when has_class_flag cl CExtern -> diff --git a/src/optimization/inlineConstructors.ml b/src/optimization/inlineConstructors.ml index 1fb7f8c71e5..1988a44c611 100644 --- a/src/optimization/inlineConstructors.ml +++ b/src/optimization/inlineConstructors.ml @@ -731,22 +731,35 @@ let inline_constructors ctx original_e = let cf = ctx.f.curfield in if !included_untyped && not (Meta.has Meta.HasUntyped cf.cf_meta) then cf.cf_meta <- (Meta.HasUntyped,[],e.epos) :: cf.cf_meta; let e = make_expr_for_rev_list el e.etype e.epos in - let rec get_pretty_name iv = match iv.iv_kind with + let rec get_pretty_name iv : string list = match iv.iv_kind with | IVKField(io,fname,None) -> begin try let is_user_variable iv = match iv.iv_var.v_kind with VUser _ | VInlined -> true | _ -> false in let iv = List.find is_user_variable io.io_aliases in - (get_pretty_name iv) ^ "_" ^ fname; + fname :: (get_pretty_name iv); with Not_found -> - (get_pretty_name (List.hd io.io_aliases)) ^ "_" ^ fname; + fname :: (get_pretty_name (List.hd io.io_aliases)); end - | _ -> iv.iv_var.v_name + | _ -> [iv.iv_var.v_name] + in + let is_user_kind iv = match iv.iv_var.v_kind with VUser _ -> true | _ -> false in + let rec was_user iv = match iv.iv_kind with + | IVKField(io,_,_) -> + begin try + let iv = List.find is_user_kind io.io_aliases in + (was_user iv); + with Not_found -> + (was_user (List.hd io.io_aliases)) ; + end + | _ -> is_user_kind iv in IntMap.iter (fun _ iv -> let v = iv.iv_var in if v.v_id < 0 then begin v.v_id <- -v.v_id; - v.v_name <- get_pretty_name iv + let vnames = List.rev (get_pretty_name iv) in + v.v_name <- String.concat "_" vnames; + if (was_user iv) then v.v_kind <- VInlinedConstructorVariable vnames; end ) !vars; e From 539601b839237ca16fde944a9d0ae5075d148eb0 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Fri, 16 Feb 2024 20:08:06 +0100 Subject: [PATCH 06/49] [macro] Build order vs inheritance (#11582) * [macro] more predictable build macro order * [tests] add macro build order test * [tests] Run our build macro before utest build macro --- src/typing/typeloadCheck.ml | 2 +- tests/misc/projects/Issue11582/Macro.macro.hx | 27 ++++++++++ tests/misc/projects/Issue11582/Main.hx | 51 +++++++++++++++++++ tests/misc/projects/Issue11582/compile.hxml | 2 + .../projects/Issue11582/compile.hxml.stdout | 13 +++++ tests/server/src/TestCase.hx | 4 +- 6 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 tests/misc/projects/Issue11582/Macro.macro.hx create mode 100644 tests/misc/projects/Issue11582/Main.hx create mode 100644 tests/misc/projects/Issue11582/compile.hxml create mode 100644 tests/misc/projects/Issue11582/compile.hxml.stdout diff --git a/src/typing/typeloadCheck.ml b/src/typing/typeloadCheck.ml index 65b9e6c956f..8924e334737 100644 --- a/src/typing/typeloadCheck.ml +++ b/src/typing/typeloadCheck.ml @@ -513,7 +513,7 @@ module Inheritance = struct match m with | Meta.AutoBuild, el, p -> c.cl_meta <- (Meta.Build,el,{ c.cl_pos with pmax = c.cl_pos.pmin }(* prevent display metadata *)) :: m :: c.cl_meta | _ -> () - ) csup.cl_meta; + ) (List.rev csup.cl_meta); if has_class_flag csup CFinal && not (((has_class_flag csup CExtern) && Meta.has Meta.Hack c.cl_meta) || (match c.cl_kind with KTypeParameter _ -> true | _ -> false)) then raise_typing_error ("Cannot extend a final " ^ if (has_class_flag c CInterface) then "interface" else "class") p; in diff --git a/tests/misc/projects/Issue11582/Macro.macro.hx b/tests/misc/projects/Issue11582/Macro.macro.hx new file mode 100644 index 00000000000..55f1d185b26 --- /dev/null +++ b/tests/misc/projects/Issue11582/Macro.macro.hx @@ -0,0 +1,27 @@ +class Macro { + static var id = 0; + static function build(i:String) { + if (haxe.macro.Context.getLocalClass().get().isInterface) return null; + + var hasMacros = false; + var fields = haxe.macro.Context.getBuildFields(); + for (f in fields) { + if (f.name == "macros") { + hasMacros = true; + break; + } + } + + if (!hasMacros) + fields = (macro class A { + public static var macros = []; + }).fields.concat(fields); + + var id = '_' + id++; + fields.push((macro class A { + static var $id = {macros.push($v{i}); 0;}; + }).fields[0]); + + return fields; + } +} diff --git a/tests/misc/projects/Issue11582/Main.hx b/tests/misc/projects/Issue11582/Main.hx new file mode 100644 index 00000000000..26f3b118d02 --- /dev/null +++ b/tests/misc/projects/Issue11582/Main.hx @@ -0,0 +1,51 @@ +class Main { + static function main() { + trace("Foo"); + trace(Foo1.macros); + trace(Foo2.macros); + trace(Foo3.macros); + trace(Foo4.macros); + + trace("Bar"); + trace(Bar1.macros); + trace(Bar2.macros); + trace(Bar3.macros); + + trace("Baz"); + trace(Baz1.macros); + trace(Baz2.macros); + trace(Baz3.macros); + } +} + +@:autoBuild(Macro.build("I1")) +interface I1 {} + +@:autoBuild(Macro.build("I2")) +interface I2 {} + +@:autoBuild(Macro.build("auto Foo1 (1)")) +@:autoBuild(Macro.build("auto Foo1 (2)")) +@:build(Macro.build("Foo1")) +class Foo1 implements I1 implements I2 {} + +@:build(Macro.build("Foo2")) +class Foo2 extends Foo1 {} + +@:build(Macro.build("Foo3 (1)")) +@:build(Macro.build("Foo3 (2)")) +class Foo3 extends Foo2 {} + +@:build(Macro.build("Foo4")) +class Foo4 extends Foo3 {} + +class Bar1 implements I2 implements I1 {} +class Bar2 extends Bar1 {} +class Bar3 extends Bar2 {} + +@:autoBuild(Macro.build("I3")) +interface I3 extends I1 {} + +class Baz1 implements I3 implements I2 {} +class Baz2 extends Baz1 {} +class Baz3 extends Baz2 {} diff --git a/tests/misc/projects/Issue11582/compile.hxml b/tests/misc/projects/Issue11582/compile.hxml new file mode 100644 index 00000000000..7d61297e2cb --- /dev/null +++ b/tests/misc/projects/Issue11582/compile.hxml @@ -0,0 +1,2 @@ +-main Main +--interp diff --git a/tests/misc/projects/Issue11582/compile.hxml.stdout b/tests/misc/projects/Issue11582/compile.hxml.stdout new file mode 100644 index 00000000000..d85a3c1e974 --- /dev/null +++ b/tests/misc/projects/Issue11582/compile.hxml.stdout @@ -0,0 +1,13 @@ +Main.hx:3: Foo +Main.hx:4: [I2,I1,Foo1] +Main.hx:5: [I2,I1,auto Foo1 (1),auto Foo1 (2),Foo2] +Main.hx:6: [I2,I1,auto Foo1 (1),auto Foo1 (2),Foo3 (1),Foo3 (2)] +Main.hx:7: [I2,I1,auto Foo1 (1),auto Foo1 (2),Foo4] +Main.hx:9: Bar +Main.hx:10: [I1,I2] +Main.hx:11: [I1,I2] +Main.hx:12: [I1,I2] +Main.hx:14: Baz +Main.hx:15: [I2,I1,I3] +Main.hx:16: [I2,I1,I3] +Main.hx:17: [I2,I1,I3] diff --git a/tests/server/src/TestCase.hx b/tests/server/src/TestCase.hx index ed83696c3c0..5f5ecc411ba 100644 --- a/tests/server/src/TestCase.hx +++ b/tests/server/src/TestCase.hx @@ -18,7 +18,9 @@ using StringTools; using Lambda; @:autoBuild(utils.macro.BuildHub.build()) -class TestCase implements ITest { +interface ITestCase {} + +class TestCase implements ITest implements ITestCase { static public var debugLastResult:{ hasError:Bool, stdout:String, From d92f08b8ebe1d98d67f031f48b774bd4e0fa5c3f Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 21 Feb 2024 07:13:04 +0100 Subject: [PATCH 07/49] Unify help messages handling (#11584) * Don't go through message reporting for help messages * [tests] Avoid (ab)using --version --- src/compiler/args.ml | 15 +++++---------- src/compiler/compiler.ml | 2 +- tests/misc/projects/Issue8471/Macro.hx | 1 + tests/misc/projects/Issue8471/Macro2.hx | 1 + tests/misc/projects/Issue8471/compile.hxml | 1 - .../Issue8471/compile2-pretty.hxml.stderr | 4 ++-- tests/misc/projects/Issue8471/compile2.hxml | 1 - .../misc/projects/Issue8471/compile2.hxml.stderr | 2 +- 8 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/compiler/args.ml b/src/compiler/args.ml index 127d84f9e6c..c3de78ce41e 100644 --- a/src/compiler/args.ml +++ b/src/compiler/args.ml @@ -154,8 +154,7 @@ let parse_args com = com.debug <- true; ),"","add debug information to the compiled code"); ("Miscellaneous",["--version"],["-version"],Arg.Unit (fun() -> - com.info s_version_full null_pos; - actx.did_something <- true; + raise (Helper.HelpMessage s_version_full); ),"","print version and exit"); ("Miscellaneous", ["-h";"--help"], ["-help"], Arg.Unit (fun () -> raise (Arg.Help "") @@ -163,31 +162,27 @@ let parse_args com = ("Miscellaneous",["--help-defines"],[], Arg.Unit (fun() -> let all,max_length = Define.get_documentation_list com.user_defines in let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in - List.iter (fun msg -> com.print (msg ^ "\n")) all; - actx.did_something <- true + raise (Helper.HelpMessage (ExtLib.String.join "\n" all)); ),"","print help for all compiler specific defines"); ("Miscellaneous",["--help-user-defines"],[], Arg.Unit (fun() -> actx.did_something <- true; com.callbacks#add_after_init_macros (fun() -> let all,max_length = Define.get_user_documentation_list com.user_defines in let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in - List.iter (fun msg -> com.print (msg ^ "\n")) all; - raise Abort + raise (Helper.HelpMessage (ExtLib.String.join "\n" all)); ) ),"","print help for all user defines"); ("Miscellaneous",["--help-metas"],[], Arg.Unit (fun() -> let all,max_length = Meta.get_documentation_list com.user_metas in let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in - List.iter (fun msg -> com.print (msg ^ "\n")) all; - actx.did_something <- true + raise (Helper.HelpMessage (ExtLib.String.join "\n" all)); ),"","print help for all compiler metadatas"); ("Miscellaneous",["--help-user-metas"],[], Arg.Unit (fun() -> actx.did_something <- true; com.callbacks#add_after_init_macros (fun() -> let all,max_length = Meta.get_user_documentation_list com.user_metas in let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in - List.iter (fun msg -> com.print (msg ^ "\n")) all; - raise Abort + raise (Helper.HelpMessage (ExtLib.String.join "\n" all)); ) ),"","print help for all user metadatas"); ] in diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index 52fef29aed9..cd7d63d2c14 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -440,7 +440,7 @@ with | Failure msg when not Helper.is_debug_run -> error ctx ("Error: " ^ msg) null_pos | Helper.HelpMessage msg -> - com.info msg null_pos + print_endline msg | Parser.TypePath (p,c,is_import,pos) -> DisplayOutput.handle_type_path_exception ctx p c is_import pos | Parser.SyntaxCompletion(kind,subj) -> diff --git a/tests/misc/projects/Issue8471/Macro.hx b/tests/misc/projects/Issue8471/Macro.hx index 0253ca3c155..2aadcbc88bf 100644 --- a/tests/misc/projects/Issue8471/Macro.hx +++ b/tests/misc/projects/Issue8471/Macro.hx @@ -2,6 +2,7 @@ import haxe.macro.Context; class Macro { public static function init() { + Context.info("Info", Context.currentPos()); Context.warning("This warning will disappear", Context.currentPos()); Context.onAfterTyping(afterTyping); diff --git a/tests/misc/projects/Issue8471/Macro2.hx b/tests/misc/projects/Issue8471/Macro2.hx index 437fd064f0f..3d85b5b70fa 100644 --- a/tests/misc/projects/Issue8471/Macro2.hx +++ b/tests/misc/projects/Issue8471/Macro2.hx @@ -9,6 +9,7 @@ class Macro2 { } static function afterTyping(_) { + Context.info("Info", Context.currentPos()); Context.warning(("1" :DeprecatedType), Context.currentPos()); Context.warning("2", Context.currentPos()); Context.warning("3", Context.currentPos()); diff --git a/tests/misc/projects/Issue8471/compile.hxml b/tests/misc/projects/Issue8471/compile.hxml index d294417d47b..a838b3a019d 100644 --- a/tests/misc/projects/Issue8471/compile.hxml +++ b/tests/misc/projects/Issue8471/compile.hxml @@ -1,2 +1 @@ ---version --macro Macro.init() diff --git a/tests/misc/projects/Issue8471/compile2-pretty.hxml.stderr b/tests/misc/projects/Issue8471/compile2-pretty.hxml.stderr index 75fed4d477c..77e260c8072 100644 --- a/tests/misc/projects/Issue8471/compile2-pretty.hxml.stderr +++ b/tests/misc/projects/Issue8471/compile2-pretty.hxml.stderr @@ -1,6 +1,6 @@ -[WARNING] (macro) Macro2.hx:12: characters 25-39 +[WARNING] (macro) Macro2.hx:13: characters 25-39 - 12 | Context.warning(("1" :DeprecatedType), Context.currentPos()); + 13 | Context.warning(("1" :DeprecatedType), Context.currentPos()); | ^^^^^^^^^^^^^^ | (WDeprecated) This typedef is deprecated in favor of String diff --git a/tests/misc/projects/Issue8471/compile2.hxml b/tests/misc/projects/Issue8471/compile2.hxml index 840524bc392..e4f8de4771c 100644 --- a/tests/misc/projects/Issue8471/compile2.hxml +++ b/tests/misc/projects/Issue8471/compile2.hxml @@ -1,2 +1 @@ ---version --macro Macro2.init() diff --git a/tests/misc/projects/Issue8471/compile2.hxml.stderr b/tests/misc/projects/Issue8471/compile2.hxml.stderr index c3b0af5feb7..8c78458c934 100644 --- a/tests/misc/projects/Issue8471/compile2.hxml.stderr +++ b/tests/misc/projects/Issue8471/compile2.hxml.stderr @@ -1,4 +1,4 @@ -Macro2.hx:12: characters 25-39 : Warning : (WDeprecated) This typedef is deprecated in favor of String +Macro2.hx:13: characters 25-39 : Warning : (WDeprecated) This typedef is deprecated in favor of String Warning : 1 Warning : 2 Warning : 3 From 342b1387e287241fac6b8300a29e7955d7bf4429 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 21 Feb 2024 10:15:16 +0100 Subject: [PATCH 08/49] [macro] Update cache dependencies for macro types too --- src/typing/macroContext.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index fc1c46f036b..5c4196187ff 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -636,6 +636,7 @@ and flush_macro_context mint mctx = FiltersCommon.remove_generic_base; Exceptions.patch_constructors mctx; (fun mt -> AddFieldInits.add_field_inits mctx.c.curclass.cl_path (RenameVars.init mctx.com) mctx.com mt); + Filters.update_cache_dependencies mctx.com; minimal_restore; ] in let ready = fun t -> From 8593fb756e70d71061e830a1a995fdb110337480 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 21 Feb 2024 13:31:36 +0100 Subject: [PATCH 09/49] [filters] Do not close monomorphs when flushing macro context --- src/filters/filters.ml | 6 +++--- src/typing/macroContext.ml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/filters/filters.ml b/src/filters/filters.ml index 4c12093f5e2..fa31925f4d2 100644 --- a/src/filters/filters.ml +++ b/src/filters/filters.ml @@ -507,7 +507,7 @@ let destruction tctx detail_times main locals = com.callbacks#run com.error_ext com.callbacks#get_after_filters; enter_stage com CFilteringDone -let update_cache_dependencies com t = +let update_cache_dependencies ~close_monomorphs com t = let visited_anons = ref [] in let rec check_t m t = match t with | TInst(c,tl) -> @@ -536,7 +536,7 @@ let update_cache_dependencies com t = check_t m t | _ -> (* Bind any still open monomorph that's part of a signature to Dynamic now (issue #10653) *) - Monomorph.do_bind r t_dynamic; + if close_monomorphs then Monomorph.do_bind r t_dynamic end | TLazy f -> check_t m (lazy_type f) @@ -743,7 +743,7 @@ let run tctx main before_destruction = enter_stage com CSaveStart; with_timer detail_times "save state" None (fun () -> List.iter (fun mt -> - update_cache_dependencies com mt; + update_cache_dependencies ~close_monomorphs:true com mt; save_class_state com mt ) new_types; ); diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index 5c4196187ff..dce64f76af1 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -636,7 +636,7 @@ and flush_macro_context mint mctx = FiltersCommon.remove_generic_base; Exceptions.patch_constructors mctx; (fun mt -> AddFieldInits.add_field_inits mctx.c.curclass.cl_path (RenameVars.init mctx.com) mctx.com mt); - Filters.update_cache_dependencies mctx.com; + Filters.update_cache_dependencies ~close_monomorphs:false mctx.com; minimal_restore; ] in let ready = fun t -> From fe211b8ea449c2484e805425f9c72df89ac11815 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 22 Feb 2024 15:45:53 +0100 Subject: [PATCH 10/49] [hxb] do not use same m_extra reference Closes #11491 --- src/compiler/server.ml | 4 +++- src/context/display/displayJson.ml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/compiler/server.ml b/src/compiler/server.ml index d009e7de25e..6ba694322b2 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -399,7 +399,9 @@ class hxb_reader_api_server m_path = path; m_types = []; m_statics = None; - m_extra = mc.mc_extra + (* Creating a new m_extra because if we keep the same reference, display requests *) + (* can alter it with bad data (for example adding dependencies that are not cached) *) + m_extra = { mc.mc_extra with m_deps = mc.mc_extra.m_deps } } method add_module (m : module_def) = diff --git a/src/context/display/displayJson.ml b/src/context/display/displayJson.ml index aaebde54db2..1563b81a46c 100644 --- a/src/context/display/displayJson.ml +++ b/src/context/display/displayJson.ml @@ -116,7 +116,9 @@ class hxb_reader_api_com m_path = path; m_types = []; m_statics = None; - m_extra = mc.mc_extra + (* Creating a new m_extra because if we keep the same reference, display requests *) + (* can alter it with bad data (for example adding dependencies that are not cached) *) + m_extra = { mc.mc_extra with m_deps = mc.mc_extra.m_deps } } method add_module (m : module_def) = From e3ee405df99e022b355ec7b6f223be074c380c45 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 21 Feb 2024 13:15:20 +0100 Subject: [PATCH 11/49] Add basic.tany --- src/context/common.ml | 2 ++ src/core/tType.ml | 1 + src/typing/typerEntry.ml | 11 +++++++++++ 3 files changed, 14 insertions(+) diff --git a/src/context/common.ml b/src/context/common.ml index 7099c8f6cdd..c662ca54a48 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -826,6 +826,7 @@ let create compilation_step cs version args display_mode = pass_debug_messages = DynArray.create(); basic = { tvoid = mk_mono(); + tany = mk_mono(); tint = mk_mono(); tfloat = mk_mono(); tbool = mk_mono(); @@ -873,6 +874,7 @@ let clone com is_macro_context = cache = None; basic = { t with tvoid = mk_mono(); + tany = mk_mono(); tint = mk_mono(); tfloat = mk_mono(); tbool = mk_mono(); diff --git a/src/core/tType.ml b/src/core/tType.ml index 876720fc849..39f5d48d8a6 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -454,6 +454,7 @@ exception Type_exception of t type basic_types = { mutable tvoid : t; + mutable tany : t; mutable tint : t; mutable tfloat : t; mutable tbool : t; diff --git a/src/typing/typerEntry.ml b/src/typing/typerEntry.ml index 9ceba485950..04111d43d27 100644 --- a/src/typing/typerEntry.ml +++ b/src/typing/typerEntry.ml @@ -127,6 +127,17 @@ let create com macros = | TClassDecl ({cl_path = ([],"Std")} as c) -> ctx.com.std <- c; | _ -> () ) m.m_types; + let m = TypeloadModule.load_module ctx ([],"Any") null_pos in + List.iter (fun mt -> match mt with + | TAbstractDecl a -> + (match snd a.a_path with + | "Any" -> + let t = TAbstract (a,[]) in + Type.unify t ctx.t.tany; + ctx.t.tany <- t; + | _ -> ()) + | _ -> () + ) m.m_types; let m = TypeloadModule.load_module ctx ([],"Array") null_pos in (try List.iter (fun t -> ( From 271043e2892186c7227cd1f3b31ddd8b16d4bc3b Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 21 Feb 2024 13:15:49 +0100 Subject: [PATCH 12/49] [filters] bind unbound monomorphs to Any instead of Dynamic --- src/filters/filters.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/filters/filters.ml b/src/filters/filters.ml index fa31925f4d2..c36464ca364 100644 --- a/src/filters/filters.ml +++ b/src/filters/filters.ml @@ -535,8 +535,8 @@ let update_cache_dependencies ~close_monomorphs com t = | Some t -> check_t m t | _ -> - (* Bind any still open monomorph that's part of a signature to Dynamic now (issue #10653) *) - if close_monomorphs then Monomorph.do_bind r t_dynamic + (* Bind any still open monomorph that's part of a signature to Any now (issue #10653) *) + if close_monomorphs then Monomorph.do_bind r com.basic.tany; end | TLazy f -> check_t m (lazy_type f) From ab884f89e136ee991af1a077319cfdd0d3d12905 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 22 Feb 2024 16:14:26 +0100 Subject: [PATCH 13/49] [tests] Add type hole test for 10653 --- tests/server/src/cases/issues/Issue10653.hx | 22 +++++++++++++++++++ .../issues/Issue10653/MainAfterWrong.hx | 9 ++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/server/test/templates/issues/Issue10653/MainAfterWrong.hx diff --git a/tests/server/src/cases/issues/Issue10653.hx b/tests/server/src/cases/issues/Issue10653.hx index 2ebfa0b4fd1..418a68c0735 100644 --- a/tests/server/src/cases/issues/Issue10653.hx +++ b/tests/server/src/cases/issues/Issue10653.hx @@ -1,5 +1,7 @@ package cases.issues; +import haxe.display.Diagnostic; + class Issue10653 extends TestCase { function test(_) { vfs.putContent("Test.hx", getTemplate("issues/Issue10653/Test.hx")); @@ -16,4 +18,24 @@ class Issue10653 extends TestCase { Assert.equals(0, res.length); }); } + + function testTypeHole(_) { + vfs.putContent("Test.hx", getTemplate("issues/Issue10653/Test.hx")); + vfs.putContent("Main.hx", getTemplate("issues/Issue10653/MainBefore.hx")); + var args = ["-main", "Main", "--js", "no.js", "--no-output"]; + runHaxe(args); + vfs.putContent("Main.hx", getTemplate("issues/Issue10653/MainAfterWrong.hx")); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(1, res.length); + var arg:MissingFieldDiagnostics = cast res[0].diagnostics[0].args; + Assert.equals("foo", arg.entries[0].fields[0].field.name); + }); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(1, res.length); + var arg:MissingFieldDiagnostics = cast res[0].diagnostics[0].args; + Assert.equals("foo", arg.entries[0].fields[0].field.name); + }); + } } diff --git a/tests/server/test/templates/issues/Issue10653/MainAfterWrong.hx b/tests/server/test/templates/issues/Issue10653/MainAfterWrong.hx new file mode 100644 index 00000000000..bfebe2386cf --- /dev/null +++ b/tests/server/test/templates/issues/Issue10653/MainAfterWrong.hx @@ -0,0 +1,9 @@ +class Main { + static function main() { + var x = Test.test(); + x = new Main(); + x.foo = "wtf"; + } + + function new() {} +} From 5957d977f0164ebbbc47f9f64924350440cfd1ef Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Fri, 23 Feb 2024 08:59:01 +0100 Subject: [PATCH 14/49] [jvm] remove redundant ordinal comparison on enums closes #11591 --- src/generators/genjvm.ml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/generators/genjvm.ml b/src/generators/genjvm.ml index 4c1a8fa664d..e8ba03fa798 100644 --- a/src/generators/genjvm.ml +++ b/src/generators/genjvm.ml @@ -2763,11 +2763,6 @@ let generate_enum_equals gctx (jc_ctor : JvmClass.builder) = else compare_standard jsig in - load(); - jm_equals#invokevirtual java_enum_path "ordinal" (method_sig [] (Some TInt)); - jm_equals#load_this; - jm_equals#invokevirtual java_enum_path "ordinal" (method_sig [] (Some TInt)); - compare TInt; let compare_field n jsig = load(); jm_equals#getfield jc_ctor#get_this_path n jsig; From 9aae69cfc7c5582728b05351019ea061f6a43739 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Fri, 23 Feb 2024 14:31:57 +0100 Subject: [PATCH 15/49] [hxb] don't reset wrote_local_type_param on nested fields Closes #11589 --- src/compiler/hxb/hxbWriter.ml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/hxb/hxbWriter.ml b/src/compiler/hxb/hxbWriter.ml index 15ecb255825..23ea698e153 100644 --- a/src/compiler/hxb/hxbWriter.ml +++ b/src/compiler/hxb/hxbWriter.ml @@ -1067,7 +1067,6 @@ module HxbWriter = struct with Not_found -> let restore = start_temporary_chunk writer 256 in let old = writer.wrote_local_type_param in - writer.wrote_local_type_param <- false; ignore(write_class_field_and_overloads_data writer true cf); let wrote_local_type_param = writer.wrote_local_type_param in writer.wrote_local_type_param <- old; From 3c97999667770f3a5418817d99a98bc47ef930b0 Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Mon, 26 Feb 2024 11:21:41 +0100 Subject: [PATCH 16/49] [hl] hlopt rework try-catch control flow (#11581) closes #11466, closes #9174 --- src/generators/hlopt.ml | 36 +++++++++++++++++++---- tests/unit/src/unit/issues/Issue11466.hx | 30 +++++++++++++++++++ tests/unit/src/unit/issues/Issue9174.hx | 37 ++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 tests/unit/src/unit/issues/Issue11466.hx create mode 100644 tests/unit/src/unit/issues/Issue9174.hx diff --git a/src/generators/hlopt.ml b/src/generators/hlopt.ml index 79fb79203c0..c56b7e5010d 100644 --- a/src/generators/hlopt.ml +++ b/src/generators/hlopt.ml @@ -47,6 +47,7 @@ type block = { mutable bneed : ISet.t; mutable bneed_all : ISet.t option; mutable bwrite : (int, int) PMap.t; + mutable btrap : int list; } type control = @@ -54,6 +55,7 @@ type control = | CJCond of int | CJAlways of int | CTry of int + | CCatch | CSwitch of int array | CRet | CThrow @@ -75,6 +77,8 @@ let control = function CSwitch cases | OTrap (_,d) -> CTry d + | OEndTrap _ -> + CCatch | _ -> CNo @@ -460,7 +464,7 @@ let code_graph (f:fundecl) = | CJAlways d | CJCond d -> Hashtbl.replace all_blocks (i + 1 + d) true | _ -> () done; - let rec make_block pos = + let rec make_block trapl pos = try Hashtbl.find blocks_pos pos with Not_found -> @@ -474,11 +478,12 @@ let code_graph (f:fundecl) = bneed = ISet.empty; bwrite = PMap.empty; bneed_all = None; + btrap = trapl; } in Hashtbl.add blocks_pos pos b; let rec loop i = - let goto d = - let b2 = make_block (i + 1 + d) in + let goto ?(tl=b.btrap) d = + let b2 = make_block tl (i + 1 + d) in b2.bprev <- b :: b2.bprev; b2 in @@ -488,7 +493,8 @@ let code_graph (f:fundecl) = end else match control (op i) with | CNo -> loop (i + 1) - | CRet | CThrow -> + | CRet -> + assert(b.btrap = []); b.bend <- i | CJAlways d -> b.bend <- i; @@ -496,9 +502,27 @@ let code_graph (f:fundecl) = | CSwitch pl -> b.bend <- i; b.bnext <- goto 0 :: Array.to_list (Array.map goto pl) - | CJCond d | CTry d -> + | CJCond d -> b.bend <- i; b.bnext <- [goto 0; goto d]; + | CTry d -> + b.bend <- i; + b.bnext <- [goto ~tl:((i+1+d)::b.btrap) 0; goto d]; + | CThrow -> + b.bend <- i; + match b.btrap with + | [] -> () + | [p] -> b.bnext <- [goto ~tl:[] (p-1-i)]; + | p :: pl -> b.bnext <- [goto ~tl:pl (p-1-i)]; + ; + | CCatch -> + let p, pl = match b.btrap with + | [] -> assert false; + | [p] -> p, [] + | p :: pl -> p, pl + in + b.bend <- i; + b.bnext <- [goto ~tl:pl 0; goto ~tl:pl (p-1-i)]; | CLabel -> b.bloop <- true; loop (i + 1) @@ -506,7 +530,7 @@ let code_graph (f:fundecl) = loop pos; b in - blocks_pos, make_block 0 + blocks_pos, make_block [] 0 type rctx = { r_root : block; diff --git a/tests/unit/src/unit/issues/Issue11466.hx b/tests/unit/src/unit/issues/Issue11466.hx new file mode 100644 index 00000000000..c401eb9b7bb --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11466.hx @@ -0,0 +1,30 @@ +package unit.issues; + +private function doThrow() { + throw "from doThrow"; +} + +class Issue11466 extends unit.Test { + var b = 10; + function test() { + var x = 0; + try { + x = b; + throw ''; + } catch(_) { + x += 1; + } + eq(11, x); + } + + function test2() { + var x = 0; + try { + x = b; + doThrow(); + } catch(_) { + x += 1; + } + eq(11, x); + } +} diff --git a/tests/unit/src/unit/issues/Issue9174.hx b/tests/unit/src/unit/issues/Issue9174.hx new file mode 100644 index 00000000000..4f3a9f8257d --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9174.hx @@ -0,0 +1,37 @@ +package unit.issues; + +private function doThrow() { + throw "from doThrow"; +} + +class Issue9174 extends unit.Test { + function test() { + var value = ""; + try { + try { + throw "from throw"; + } catch (e:String) { + value += "inner catch"; + throw e; + } + } catch (e:String) { + value += ", outer catch, " + e; + } + eq("inner catch, outer catch, from throw", value); + } + + function test2() { + var value = ""; + try { + try { + doThrow(); + } catch (e:String) { + value += "inner catch"; + throw e; + } + } catch (e:String) { + value += ", outer catch, " + e; + } + eq("inner catch, outer catch, from doThrow", value); + } +} From 52888e2600bccfef0f1fc2970c396b5096d2e2f6 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Mon, 4 Mar 2024 11:10:28 +0100 Subject: [PATCH 17/49] update changelog --- extra/CHANGES.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/extra/CHANGES.txt b/extra/CHANGES.txt index a1ca8221f44..42bd5b671c7 100644 --- a/extra/CHANGES.txt +++ b/extra/CHANGES.txt @@ -1,3 +1,34 @@ +2024-03-04 4.3.4 + + General improvements: + + all : allow @:using with Class and Enum (#11553) + display : expose list of metadata/defines (#11399) + + Bugfixes: + + all : typedef vs. GADT (#11446) + all : don't double-throw exceptions (#11175) + all : fix some abstract inlining failures (#11526) + all : fix JsonPrinter empty parent class (#11560) + all : dce: clean up operator handling (#11427) + all : analyzer: deal with unreachable block in binops (#11402) + all : analyzer: don't recursively check enum values when const propagating (#11429) + all : analyzer: fix check for inlined purity meta + display : fix errors from parser missing in diagnostics (#8687) + display : fix display services with static extension (#11285) + display : fix display services with safe navigation (#11205) + hl : hlopt rework try-catch control flow (#11581) + hl/c : fix reserved keywords (#11408) + + Deprecation / future version handling: + + all : don't infer string on concat, when using -D haxe-next (#11318) + all : handle optional arguments with bind, when using -D haxe-next (#11533) + macro : build order vs inheritance, when using -D haxe-next (#11582) + macro : deprecate some API from haxe.macro.Compiler (see #11540) + java/jvm : warn about --java ... -D jvm vs --jvm ... + 2023-09-17 4.3.3 General improvements: From 603f6f6c17c5183e26b78cbdac6bf36884759f1c Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Tue, 12 Mar 2024 11:08:44 +0100 Subject: [PATCH 18/49] [message reporting] Update sub errors handling (#11595) * deal with some sub error TODO * Add misc test for 'Called from macro here' sub error * Handle more sub error TODO * usual List.rev List.rev x * More TODOs * Handle more sub errors * Update tests * Last (?) sub error TODO * [tests] Update expected result with sub error --- src/compiler/compiler.ml | 4 +- src/filters/localStatic.ml | 6 +-- src/optimization/analyzerTexpr.ml | 5 +- src/optimization/inlineConstructors.ml | 6 +-- src/typing/callUnification.ml | 22 ++++---- src/typing/fields.ml | 5 +- src/typing/generic.ml | 12 ++--- src/typing/typeload.ml | 32 ++++++------ src/typing/typeloadCheck.ml | 50 ++++++++++--------- src/typing/typeloadFields.ml | 30 ++++++----- src/typing/typeloadModule.ml | 5 +- src/typing/typer.ml | 8 +-- .../Issue2969/compile-fail.hxml.stderr | 4 +- .../Issue3361/compile1-fail.hxml.stderr | 4 +- .../Issue3361/compile2-fail.hxml.stderr | 4 +- .../Issue3417/compile-fail.hxml.stderr | 4 +- .../Issue4378/compile-fail.hxml.stderr | 4 +- .../Issue6584/pretty-fail.hxml.stderr | 8 ++- .../Issue6796/pretty-fail.hxml.stderr | 3 +- .../Issue8283/compile-fail.hxml.stderr | 1 - .../Issue8828/compile2-fail.hxml.stderr | 2 +- .../Issue8828/compile3-fail.hxml.stderr | 2 +- .../compile-fail.hxml.stderr | 2 +- tests/misc/projects/IssueXXXXX/Main.hx | 11 ++++ tests/misc/projects/IssueXXXXX/Main2.hx | 19 +++++++ tests/misc/projects/IssueXXXXX/Main3.hx | 22 ++++++++ .../projects/IssueXXXXX/compile-fail.hxml | 1 + .../IssueXXXXX/compile-fail.hxml.stderr | 2 + .../projects/IssueXXXXX/compile2-fail.hxml | 1 + .../IssueXXXXX/compile2-fail.hxml.stderr | 4 ++ .../projects/IssueXXXXX/compile3-fail.hxml | 1 + .../IssueXXXXX/compile3-fail.hxml.stderr | 12 +++++ tests/unit/src/unit/issues/Issue3714.hx | 2 +- 33 files changed, 188 insertions(+), 110 deletions(-) create mode 100644 tests/misc/projects/IssueXXXXX/Main.hx create mode 100644 tests/misc/projects/IssueXXXXX/Main2.hx create mode 100644 tests/misc/projects/IssueXXXXX/Main3.hx create mode 100644 tests/misc/projects/IssueXXXXX/compile-fail.hxml create mode 100644 tests/misc/projects/IssueXXXXX/compile-fail.hxml.stderr create mode 100644 tests/misc/projects/IssueXXXXX/compile2-fail.hxml create mode 100644 tests/misc/projects/IssueXXXXX/compile2-fail.hxml.stderr create mode 100644 tests/misc/projects/IssueXXXXX/compile3-fail.hxml create mode 100644 tests/misc/projects/IssueXXXXX/compile3-fail.hxml.stderr diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index cd7d63d2c14..34f68860c14 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -430,8 +430,8 @@ with ctx.has_error <- false; ctx.messages <- []; end else begin - error ctx (Printf.sprintf "You cannot access the %s package while %s (for %s)" pack (if pf = "macro" then "in a macro" else "targeting " ^ pf) (s_type_path m) ) p; - List.iter (error ~depth:1 ctx (Error.compl_msg "referenced here")) (List.rev pl); + let sub = List.map (fun p -> Error.make_error ~depth:1 (Error.Custom (Error.compl_msg "referenced here")) p) pl in + error_ext ctx (Error.make_error (Error.Custom (Printf.sprintf "You cannot access the %s package while %s (for %s)" pack (if pf = "macro" then "in a macro" else "targeting " ^ pf) (s_type_path m))) ~sub p) end | Error.Error err -> error_ext ctx err diff --git a/src/filters/localStatic.ml b/src/filters/localStatic.ml index e2560ae6c5b..3f462265d07 100644 --- a/src/filters/localStatic.ml +++ b/src/filters/localStatic.ml @@ -1,4 +1,3 @@ -open Common open Type open Typecore open Error @@ -14,8 +13,9 @@ let promote_local_static lsctx run v eo = let c = lsctx.ctx.c.curclass in begin try let cf = PMap.find name c.cl_statics in - display_error lsctx.ctx.com (Printf.sprintf "The expanded name of this local (%s) conflicts with another static field" name) v.v_pos; - raise_typing_error ~depth:1 "Conflicting field was found here" cf.cf_name_pos; + raise_typing_error_ext (make_error (Custom (Printf.sprintf "The expanded name of this local (%s) conflicts with another static field" name)) ~sub:[ + make_error ~depth:1 (Custom "Conflicting field was found here") cf.cf_name_pos + ] v.v_pos); with Not_found -> let cf = mk_field name ~static:true v.v_type v.v_pos v.v_pos in cf.cf_meta <- v.v_meta; diff --git a/src/optimization/analyzerTexpr.ml b/src/optimization/analyzerTexpr.ml index dc9aa066429..91637e66f8c 100644 --- a/src/optimization/analyzerTexpr.ml +++ b/src/optimization/analyzerTexpr.ml @@ -1250,8 +1250,9 @@ module Purity = struct begin try apply_to_class com c with Purity_conflict(impure,p) -> - com.error "Impure field overrides/implements field which was explicitly marked as @:pure" impure.pn_field.cf_pos; - Error.raise_typing_error ~depth:1 (Error.compl_msg "Pure field is here") p; + Error.raise_typing_error_ext (Error.make_error (Custom "Impure field overrides/implements field which was explicitly marked as @:pure") ~sub:[ + Error.make_error ~depth:1 (Custom (Error.compl_msg "Pure field is here")) p + ] impure.pn_field.cf_pos) end | _ -> () ) com.types; diff --git a/src/optimization/inlineConstructors.ml b/src/optimization/inlineConstructors.ml index 1988a44c611..050bf113ceb 100644 --- a/src/optimization/inlineConstructors.ml +++ b/src/optimization/inlineConstructors.ml @@ -131,9 +131,9 @@ let inline_constructors ctx original_e = | IOKCtor(ioc) -> List.iter (fun v -> if v.v_id < 0 then cancel_v v p) io.io_dependent_vars; if ioc.ioc_forced then begin - (* TODO construct error with sub *) - display_error ctx.com "Forced inline constructor could not be inlined" io.io_pos; - display_error ~depth:1 ctx.com (compl_msg "Cancellation happened here") p; + display_error_ext ctx.com (make_error (Custom "Forced inline constructor could not be inlined") ~sub:([ + (make_error ~depth:1 (Custom (compl_msg "Cancellation happened here")) p) + ]) io.io_pos); end | _ -> () end diff --git a/src/typing/callUnification.ml b/src/typing/callUnification.ml index 623c0fe4ed6..23c3d730373 100644 --- a/src/typing/callUnification.ml +++ b/src/typing/callUnification.ml @@ -14,7 +14,6 @@ let unify_call_args ctx el args r callp inline force_inline in_overload = let msg = ("For " ^ (if opt then "optional " else "") ^ "function argument '" ^ name ^ "'") in let e = match e.err_message with | Unify l -> { e with err_message = Unify (l @ [(Unify_custom msg)])} - | Custom parent -> { e with err_message = Custom (parent ^ "\n" ^ msg)} | _ -> { e with err_sub = (make_error (Custom (compl_msg msg)) e.err_pos) :: e.err_sub } in raise_error { e with err_message = (Call_error (Could_not_unify e.err_message)) } @@ -415,9 +414,8 @@ let unify_field_call ctx fa el_typed el p inline = p ) :: acc ) [] failures in - - display_error_ext ctx.com (make_error ~sub (Custom "Could not find a suitable overload, reasons follow") p); - raise_typing_error_ext (make_error ~depth:1 (Custom "End of overload failure reasons") p) + let sub = (make_error ~depth:1 (Custom "End of overload failure reasons") p) :: sub in + raise_typing_error_ext (make_error ~sub (Custom "Could not find a suitable overload, reasons follow") p) | Some err -> raise_typing_error_ext err end @@ -429,12 +427,11 @@ let unify_field_call ctx fa el_typed el p inline = maybe_check_access fcc.fc_field; commit_delayed_display fcc | fcc :: l -> - (* TODO construct error with sub *) - display_error ctx.com "Ambiguous overload, candidates follow" p; let st = s_type (print_context()) in - List.iter (fun fcc -> - display_error ~depth:1 ctx.com (compl_msg (st fcc.fc_type)) fcc.fc_field.cf_name_pos; - ) (fcc :: l); + let sub = List.map (fun fcc -> + make_error ~depth:1 (Custom (compl_msg (st fcc.fc_type))) fcc.fc_field.cf_name_pos + ) (fcc :: l) in + display_error_ext ctx.com (make_error (Custom "Ambiguous overload, candidates follow") ~sub:(List.rev sub) p); commit_delayed_display fcc end else begin match List.rev candidates with | [] -> fail() @@ -513,9 +510,10 @@ object(self) let ep = err.err_pos in (* display additional info in the case the error is not part of our original call *) if ep.pfile <> p.pfile || ep.pmax < p.pmin || ep.pmin > p.pmax then begin - old (if (ep = null_pos) then { err with err_pos = p } else err); - (* TODO add as sub for above error *) - if ep <> null_pos then old (make_error ~depth:(err.err_depth+1) (Custom (compl_msg "Called from macro here")) p); + if ep = null_pos then + old { err with err_pos = p } + else + old { err with err_sub = (make_error ~depth:(err.err_depth+1) (Custom (compl_msg "Called from macro here")) p) :: err.err_sub } end else old err; ); diff --git a/src/typing/fields.ml b/src/typing/fields.ml index a29be9a11f0..356a365303a 100644 --- a/src/typing/fields.ml +++ b/src/typing/fields.ml @@ -221,8 +221,9 @@ let field_access ctx mode f fh e pfield = if bypass_accessor then ( (match e.eexpr with TLocal _ when Common.defined ctx.com Define.Haxe3Compat -> warning ctx WTemp "Field set has changed here in Haxe 4: call setter explicitly to keep Haxe 3.x behaviour" pfield | _ -> ()); if not (is_physical_field f) then begin - display_error ctx.com "This field cannot be accessed because it is not a real variable" pfield; - display_error ctx.com "Add @:isVar here to enable it" f.cf_pos; + display_error_ext ctx.com (make_error (Custom "This field cannot be accessed because it is not a real variable") ~sub:[ + make_error ~depth:1 (Custom "Add @:isVar here to enable it") f.cf_pos + ] pfield); end; normal false ) diff --git a/src/typing/generic.ml b/src/typing/generic.ml index 32dcdbd9f24..22ef367f376 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -355,9 +355,9 @@ let build_generic_class ctx c p tl = | None -> begin match cf_old.cf_kind with | Method _ when not (has_class_flag c CInterface) && not (has_class_flag c CExtern) && not (has_class_field_flag cf_old CfAbstract) -> - (* TODO use sub error *) - display_error ctx.com (Printf.sprintf "Field %s has no expression (possible typing order issue)" cf_new.cf_name) cf_new.cf_pos; - display_error ctx.com (Printf.sprintf "While building %s" (s_type_path cg.cl_path)) p; + display_error_ext ctx.com (make_error (Custom (Printf.sprintf "Field %s has no expression (possible typing order issue)" cf_new.cf_name)) ~sub:([ + (make_error ~depth:1 (Custom (compl_msg (Printf.sprintf "While building %s" (s_type_path cg.cl_path)))) p) + ]) cf_new.cf_pos); | _ -> () end @@ -498,9 +498,9 @@ let type_generic_function ctx fa fcc with_type p = ignore(follow cf.cf_type); let rec check e = match e.eexpr with | TNew({cl_kind = KTypeParameter _} as c,_,_) when not (TypeloadCheck.is_generic_parameter ctx c) -> - (* TODO use sub error *) - display_error ctx.com "Only generic type parameters can be constructed" e.epos; - display_error ctx.com "While specializing this call" p; + display_error_ext ctx.com (make_error (Custom "Only generic type parameters can be constructed") ~sub:([ + (make_error ~depth:1 (Custom (compl_msg "While specializing this call")) p) + ]) e.epos); | _ -> Type.iter check e in diff --git a/src/typing/typeload.ml b/src/typing/typeload.ml index cc3ec45e541..17bb4b58aad 100644 --- a/src/typing/typeload.ml +++ b/src/typing/typeload.ml @@ -55,18 +55,18 @@ let check_field_access ctx cff = try let _,p2 = List.find (fun (access',_) -> access = access') acc in if p1 <> null_pos && p2 <> null_pos then begin - (* TODO error with sub *) - display_error ctx.com (Printf.sprintf "Duplicate access modifier %s" (Ast.s_access access)) p1; - display_error ~depth:1 ctx.com (compl_msg "Previously defined here") p2; + display_error_ext ctx.com (make_error (Custom (Printf.sprintf "Duplicate access modifier %s" (Ast.s_access access))) ~sub:([ + (make_error ~depth:1 (Custom (compl_msg "Previously defined here")) p2); + ]) p1); end; loop p1 acc l with Not_found -> match access with | APublic | APrivate -> begin try let _,p2 = List.find (fun (access',_) -> match access' with APublic | APrivate -> true | _ -> false) acc in - (* TODO error with sub *) - display_error ctx.com (Printf.sprintf "Conflicting access modifier %s" (Ast.s_access access)) p1; - display_error ~depth:1 ctx.com (compl_msg "Conflicts with this") p2; + display_error_ext ctx.com (make_error (Custom (Printf.sprintf "Conflicting access modifier %s" (Ast.s_access access))) ~sub:([ + (make_error ~depth:1 (Custom (compl_msg "Conflicts with this")) p2); + ]) p1); loop p1 acc l with Not_found -> loop p1 ((access,p1) :: acc) l @@ -244,10 +244,10 @@ let is_redefined ctx cf1 fields p = let cf2 = PMap.find cf1.cf_name fields in let st = s_type (print_context()) in if not (type_iseq cf1.cf_type cf2.cf_type) then begin - (* TODO construct error with sub? *) - display_error ctx.com ("Cannot redefine field " ^ cf1.cf_name ^ " with different type") p; - display_error ctx.com ("First type was " ^ (st cf1.cf_type)) cf1.cf_pos; - raise_typing_error ("Second type was " ^ (st cf2.cf_type)) cf2.cf_pos + raise_typing_error_ext (make_error (Custom ("Cannot redefine field " ^ cf1.cf_name ^ " with different type")) ~sub:([ + (make_error ~depth:1 (Custom (compl_msg ("Second type was " ^ (st cf2.cf_type)))) cf2.cf_pos); + (make_error ~depth:1 (Custom (compl_msg ("First type was " ^ (st cf1.cf_type)))) cf1.cf_pos); + ]) p) end else true with Not_found -> @@ -844,9 +844,9 @@ let init_core_api ctx c = | Invalid_argument _ -> raise_typing_error "Type parameters must have the same number of constraints as core type" c.cl_pos | Unify_error l -> - (* TODO send as one call with sub errors *) - display_error ctx.com ("Type parameter " ^ ttp2.ttp_name ^ " has different constraint than in core type") c.cl_pos; - display_error ctx.com (error_msg (Unify l)) c.cl_pos; + display_error_ext ctx.com (make_error (Custom ("Type parameter " ^ ttp2.ttp_name ^ " has different constraint than in core type")) ~sub:([ + (make_error ~depth:1 (Custom (compl_msg (error_msg (Unify l)))) c.cl_pos); + ]) c.cl_pos); ) ccore.cl_params c.cl_params; with Invalid_argument _ -> raise_typing_error "Class must have the same number of type parameters as core type" c.cl_pos @@ -859,9 +859,9 @@ let init_core_api ctx c = (try type_eq EqCoreType (apply_params ccore.cl_params (extract_param_types c.cl_params) f.cf_type) f2.cf_type with Unify_error l -> - (* TODO send as one call with sub errors *) - display_error ctx.com ("Field " ^ f.cf_name ^ " has different type than in core type") p; - display_error ctx.com (error_msg (Unify l)) p); + display_error_ext ctx.com (make_error (Custom ("Field " ^ f.cf_name ^ " has different type than in core type")) ~sub:([ + (make_error ~depth:1 (Custom (compl_msg (error_msg (Unify l)))) p); + ]) p)); if (has_class_field_flag f2 CfPublic) <> (has_class_field_flag f CfPublic) then raise_typing_error ("Field " ^ f.cf_name ^ " has different visibility than core type") p; (match f2.cf_doc with | None -> f2.cf_doc <- f.cf_doc diff --git a/src/typing/typeloadCheck.ml b/src/typing/typeloadCheck.ml index 8924e334737..99f1b390370 100644 --- a/src/typing/typeloadCheck.ml +++ b/src/typing/typeloadCheck.ml @@ -132,9 +132,9 @@ let copy_meta meta_src meta_target sl = let check_native_name_override ctx child base = let error base_pos child_pos = - (* TODO construct error *) - display_error ctx.com ("Field " ^ child.cf_name ^ " has different @:native value than in superclass") child_pos; - display_error ~depth:1 ctx.com (compl_msg "Base field is defined here") base_pos + display_error_ext ctx.com (make_error (Custom ("Field " ^ child.cf_name ^ " has different @:native value than in superclass")) ~sub:([ + (make_error ~depth:1 (Custom (compl_msg "Base field is defined here")) base_pos) + ]) child_pos); in try let child_name, child_pos = Naming.get_native_name child.cf_meta in @@ -189,10 +189,10 @@ let check_override_field ctx p rctx = valid_redefinition rctx.map rctx.map rctx.cf_new rctx.cf_new.cf_type rctx.cf_old rctx.t_old; with Unify_error l -> - (* TODO construct error with sub *) - display_error ctx.com ("Field " ^ i ^ " overrides parent class with different or incomplete type") p; - display_error ~depth:1 ctx.com (compl_msg "Base field is defined here") rctx.cf_old.cf_name_pos; - display_error ~depth:1 ctx.com (compl_msg (error_msg (Unify l))) p + display_error_ext ctx.com (make_error (Custom ("Field " ^ i ^ " overrides parent class with different or incomplete type")) ~sub:([ + (make_error ~depth:1 (Custom (compl_msg (error_msg (Unify l)))) p); + (make_error ~depth:1 (Custom (compl_msg "Base field is defined here")) rctx.cf_old.cf_name_pos); + ]) p) let find_override_field ctx c_new cf_new c_old tl get_super_field is_overload p = let i = cf_new.cf_name in @@ -400,10 +400,10 @@ module Inheritance = struct with Unify_error l -> if not ((has_class_flag c CExtern)) then begin - (* TODO construct error with sub *) - display_error com ("Field " ^ f.cf_name ^ " has different type than in " ^ s_type_path intf.cl_path) p; - display_error ~depth:1 com (compl_msg "Interface field is defined here") f.cf_pos; - display_error ~depth:1 com (compl_msg (error_msg (Unify l))) p; + display_error_ext com (make_error (Custom ("Field " ^ f.cf_name ^ " has different type than in " ^ s_type_path intf.cl_path)) ~sub:([ + (make_error ~depth:1 (Custom (compl_msg (error_msg (Unify l)))) p); + (make_error ~depth:1 (Custom (compl_msg "Interface field is defined here")) f.cf_name_pos); + ]) p) end ) with Not_found -> @@ -490,20 +490,19 @@ module Inheritance = struct let display = ctx.com.display_information in display.module_diagnostics <- MissingFields diag :: display.module_diagnostics | l -> - let singular = match l with [_] -> true | _ -> false in - display_error ctx.com (Printf.sprintf "This class extends abstract class %s but doesn't implement the following method%s" (s_type_path csup.cl_path) (if singular then "" else "s")) c.cl_name_pos; - (* TODO sub error ? *) - display_error ctx.com (Printf.sprintf "Implement %s or make %s abstract as well" (if singular then "it" else "them") (s_type_path c.cl_path)) c.cl_name_pos; let pctx = print_context() in - List.iter (fun (cf,_) -> + let sub = List.map (fun (cf,_) -> let s = match follow cf.cf_type with | TFun(tl,tr) -> String.concat ", " (List.map (fun (n,o,t) -> Printf.sprintf "%s:%s" n (s_type pctx t)) tl) | t -> s_type pctx t in - display_error ~depth:1 ctx.com (compl_msg (Printf.sprintf "%s(%s)" cf.cf_name s)) cf.cf_name_pos - ) (List.rev !missing) + make_error ~depth:1 (Custom (compl_msg (Printf.sprintf "%s(%s)" cf.cf_name s))) cf.cf_name_pos + ) !missing in + let singular = match l with [_] -> true | _ -> false in + let sub = [make_error (Custom (Printf.sprintf "Implement %s or make %s abstract as well" (if singular then "it" else "them") (s_type_path c.cl_path))) ~sub c.cl_name_pos] in + display_error_ext ctx.com (make_error (Custom (Printf.sprintf "This class extends abstract class %s but doesn't implement the following method%s" (s_type_path csup.cl_path) (if singular then "" else "s"))) ~sub c.cl_name_pos) let set_heritance ctx c herits p = let is_lib = Meta.has Meta.LibType c.cl_meta in @@ -644,10 +643,13 @@ let check_final_vars ctx e = Type.iter find_inits e in find_inits e; - if Hashtbl.length final_vars > 0 then - display_error ctx.com "Some final fields are uninitialized in this class" ctx.c.curclass.cl_name_pos; - DynArray.iter (fun (c,cf) -> - if Hashtbl.mem final_vars cf.cf_name then - display_error ~depth:1 ctx.com "Uninitialized field" cf.cf_name_pos - ) ordered_fields + if Hashtbl.length final_vars > 0 then begin + let sub = List.filter_map (fun (c,cf) -> + if Hashtbl.mem final_vars cf.cf_name then + Some (make_error ~depth:1 (Custom "Uninitialized field") cf.cf_name_pos) + else + None + ) (DynArray.to_list ordered_fields) in + display_error_ext ctx.com (make_error (Custom "Some final fields are uninitialized in this class") ~sub:(List.rev sub) ctx.c.curclass.cl_name_pos) + end end diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index 0090850fca4..55860c9ef63 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -313,8 +313,9 @@ let build_enum_abstract ctx c a fields p = | VUnknown -> () | VPublic(access,p2) | VPrivate(access,p2) -> - display_error ctx.com (Printf.sprintf "Conflicting access modifier %s" (Ast.s_access access)) p1; - display_error ~depth:1 ctx.com "Conflicts with this" p2; + display_error_ext ctx.com (make_error (Custom (Printf.sprintf "Conflicting access modifier %s" (Ast.s_access access))) ~sub:[ + make_error ~depth:1 (Custom (compl_msg "Conflicts with this")) p2; + ] p1) in let rec loop visibility acc = match acc with | (AExtern,p) :: acc -> @@ -551,8 +552,9 @@ let create_typer_context_for_field ctx cctx fctx cff = else if fctx.is_inline then invalid_modifier_combination fctx ctx.com fctx "abstract" "inline" (pos cff.cff_name) else if not (has_class_flag c CAbstract) then begin - display_error ctx.com "This class should be declared abstract because it has at least one abstract field" c.cl_name_pos; - display_error ctx.com "First abstract field was here" (pos cff.cff_name); + display_error_ext ctx.com (make_error (Custom "This class should be declared abstract because it has at least one abstract field") ~sub:[ + make_error ~depth:1 (Custom (compl_msg "First abstract field was here")) (pos cff.cff_name); + ] c.cl_name_pos); add_class_flag c CAbstract; end; end; @@ -1399,8 +1401,9 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p = try (match f2.cf_kind with | Method MethMacro -> - display_error ctx.com (f2.cf_name ^ ": Macro methods cannot be used as property accessor") p; - display_error ~depth:1 ctx.com (compl_msg (f2.cf_name ^ ": Accessor method is here")) f2.cf_pos; + display_error_ext ctx.com (make_error (Custom (f2.cf_name ^ ": Macro methods cannot be used as property accessor")) ~sub:[ + make_error ~depth:1 (Custom (compl_msg (f2.cf_name ^ ": Accessor method is here"))) f2.cf_pos; + ] p); | _ -> ()); unify_raise t2 t f2.cf_pos; if (fctx.is_abstract_member && not (has_class_field_flag f2 CfImpl)) || (has_class_field_flag f2 CfImpl && not (fctx.is_abstract_member)) then @@ -1556,8 +1559,9 @@ let check_overload ctx f fs is_extern_class = Overloads.same_overload_args f.cf_type f2.cf_type f f2 ) fs in - display_error ctx.com ("Another overloaded field of same signature was already declared : " ^ f.cf_name) f.cf_pos; - display_error ~depth:1 ctx.com (compl_msg "The second field is declared here") f2.cf_pos; + display_error_ext ctx.com (make_error (Custom ("Another overloaded field of same signature was already declared : " ^ f.cf_name)) ~sub:[ + make_error ~depth:1 (Custom (compl_msg "The second field is declared here")) f2.cf_pos; + ] f.cf_pos); false with Not_found -> try if ctx.com.platform <> Jvm || is_extern_class then raise Not_found; @@ -1570,12 +1574,11 @@ let check_overload ctx f fs is_extern_class = in (* Don't bother checking this on externs and assume the users know what they're doing (issue #11131) *) if has_class_field_flag f CfExtern && has_class_field_flag f2 CfExtern then raise Not_found; - display_error ctx.com ( + display_error_ext ctx.com (make_error (Custom ( "Another overloaded field of similar signature was already declared : " ^ f.cf_name ^ "\nThe signatures are different in Haxe, but not in the target language" - ) f.cf_pos; - display_error ~depth:1 ctx.com (compl_msg "The second field is declared here") f2.cf_pos; + )) ~sub:[make_error ~depth:1 (Custom (compl_msg "The second field is declared here")) f2.cf_pos] f.cf_pos); false with Not_found -> true @@ -1767,8 +1770,9 @@ let init_class ctx_c cctx c p herits fields = let display = com.display_information in display.module_diagnostics <- MissingFields diag :: display.module_diagnostics end else begin - display_error com "This class has uninitialized final vars, which requires a constructor" p; - display_error com "Example of an uninitialized final var" cf.cf_name_pos; + display_error_ext com (make_error (Custom "This class has uninitialized final vars, which requires a constructor") ~sub:[ + make_error ~depth:1 (Custom "Example of an uninitialized final var") cf.cf_name_pos; + ] p); end | _ -> () diff --git a/src/typing/typeloadModule.ml b/src/typing/typeloadModule.ml index 1b91133d29f..1d66ea81909 100644 --- a/src/typing/typeloadModule.ml +++ b/src/typing/typeloadModule.ml @@ -77,8 +77,9 @@ module ModuleLevel = struct let check_name name meta also_statics p = DeprecationCheck.check_is com ctx_m.m.curmod meta [] name meta p; let error prev_pos = - display_error com ("Name " ^ name ^ " is already defined in this module") p; - raise_typing_error ~depth:1 (compl_msg "Previous declaration here") prev_pos; + raise_typing_error_ext (make_error (Custom ("Name " ^ name ^ " is already defined in this module")) ~sub:[ + make_error ~depth:1 (Custom (compl_msg "Previous declaration here")) prev_pos + ] p); in DynArray.iter (fun t2 -> if snd (t_path t2) = name then error (t_infos t2).mt_name_pos diff --git a/src/typing/typer.ml b/src/typing/typer.ml index c3dbc68d239..7d5efa84305 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -1159,8 +1159,9 @@ and type_map_declaration ctx e1 el with_type p = let check_key e_key = try let p = Hashtbl.find keys e_key.eexpr in - display_error ctx.com "Duplicate key" e_key.epos; - raise_typing_error ~depth:1 (compl_msg "Previously defined here") p + raise_typing_error_ext (make_error (Custom "Duplicate key") ~sub:[ + make_error ~depth:1 (Custom (compl_msg "Previously defined here")) p + ] e_key.epos); with Not_found -> begin match e_key.eexpr with | TConst _ -> Hashtbl.add keys e_key.eexpr e_key.epos; @@ -1431,8 +1432,7 @@ and type_array_decl ctx el with_type p = if !allow_array_dynamic || ctx.f.untyped || ignore_error ctx.com then t_dynamic else begin - display_error ctx.com "Arrays of mixed types are only allowed if the type is forced to Array" err.err_pos; - raise_error err + raise_typing_error_ext (make_error (Custom "Arrays of mixed types are only allowed if the type is forced to Array") ~sub:[err] err.err_pos) end in mk (TArrayDecl el) (ctx.t.tarray t) p diff --git a/tests/misc/projects/Issue2969/compile-fail.hxml.stderr b/tests/misc/projects/Issue2969/compile-fail.hxml.stderr index 3f5f141700b..9196c276194 100644 --- a/tests/misc/projects/Issue2969/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue2969/compile-fail.hxml.stderr @@ -1,5 +1,5 @@ Main.hx:10: characters 18-19 : Field a has different type than in A -Main.hx:2: characters 2-29 : ... Interface field is defined here +Main.hx:2: characters 18-19 : ... Interface field is defined here Main.hx:10: characters 18-19 : ... error: Int should be String Main.hx:10: characters 18-19 : ... have: (...) -> Int -Main.hx:10: characters 18-19 : ... want: (...) -> String \ No newline at end of file +Main.hx:10: characters 18-19 : ... want: (...) -> String diff --git a/tests/misc/projects/Issue3361/compile1-fail.hxml.stderr b/tests/misc/projects/Issue3361/compile1-fail.hxml.stderr index 07b095b02f7..a33c80439d2 100644 --- a/tests/misc/projects/Issue3361/compile1-fail.hxml.stderr +++ b/tests/misc/projects/Issue3361/compile1-fail.hxml.stderr @@ -1,5 +1,5 @@ Main.hx:6: characters 13-14 : Field v has different type than in I -Main.hx:2: characters 2-29 : ... Interface field is defined here +Main.hx:2: characters 13-14 : ... Interface field is defined here Main.hx:6: characters 13-14 : ... error: String should be Dynamic Main.hx:6: characters 13-14 : ... have: (Dynamic) -> ... -Main.hx:6: characters 13-14 : ... want: (String) -> ... \ No newline at end of file +Main.hx:6: characters 13-14 : ... want: (String) -> ... diff --git a/tests/misc/projects/Issue3361/compile2-fail.hxml.stderr b/tests/misc/projects/Issue3361/compile2-fail.hxml.stderr index 9177870eb93..680c1805c03 100644 --- a/tests/misc/projects/Issue3361/compile2-fail.hxml.stderr +++ b/tests/misc/projects/Issue3361/compile2-fail.hxml.stderr @@ -1,5 +1,5 @@ Main2.hx:6: characters 26-27 : Field f has different type than in I -Main2.hx:2: characters 2-44 : ... Interface field is defined here +Main2.hx:2: characters 26-27 : ... Interface field is defined here Main2.hx:6: characters 26-27 : ... error: String should be Dynamic Main2.hx:6: characters 26-27 : ... have: (Dynamic) -> ... -Main2.hx:6: characters 26-27 : ... want: (String) -> ... \ No newline at end of file +Main2.hx:6: characters 26-27 : ... want: (String) -> ... diff --git a/tests/misc/projects/Issue3417/compile-fail.hxml.stderr b/tests/misc/projects/Issue3417/compile-fail.hxml.stderr index 47c3b02fbe9..d16b58c0179 100644 --- a/tests/misc/projects/Issue3417/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue3417/compile-fail.hxml.stderr @@ -1,3 +1,3 @@ Main.hx:6: characters 21-22 : Field f has different type than in I -Main.hx:2: characters 5-28 : ... Interface field is defined here -Main.hx:6: characters 21-22 : ... Different number of function arguments \ No newline at end of file +Main.hx:2: characters 14-15 : ... Interface field is defined here +Main.hx:6: characters 21-22 : ... Different number of function arguments diff --git a/tests/misc/projects/Issue4378/compile-fail.hxml.stderr b/tests/misc/projects/Issue4378/compile-fail.hxml.stderr index be3ea17bcd8..289921834b9 100644 --- a/tests/misc/projects/Issue4378/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue4378/compile-fail.hxml.stderr @@ -1,5 +1,5 @@ Main.hx:5: characters 18-22 : Field test has different type than in I -Main.hx:16: characters 2-32 : ... Interface field is defined here +Main.hx:16: characters 11-15 : ... Interface field is defined here Main.hx:5: characters 18-22 : ... error: String should be Dynamic Main.hx:5: characters 18-22 : ... have: (Dynamic) -> ... -Main.hx:5: characters 18-22 : ... want: (String) -> ... \ No newline at end of file +Main.hx:5: characters 18-22 : ... want: (String) -> ... diff --git a/tests/misc/projects/Issue6584/pretty-fail.hxml.stderr b/tests/misc/projects/Issue6584/pretty-fail.hxml.stderr index 95320545d68..1bc17c69b13 100644 --- a/tests/misc/projects/Issue6584/pretty-fail.hxml.stderr +++ b/tests/misc/projects/Issue6584/pretty-fail.hxml.stderr @@ -6,9 +6,7 @@ | | This class has uninitialized final vars, which requires a constructor -[ERROR] Main5.hx:2: characters 8-9 - - 2 | final v:Int; - | ^ - | Example of an uninitialized final var + 2 | final v:Int; + | ^ + | Example of an uninitialized final var diff --git a/tests/misc/projects/Issue6796/pretty-fail.hxml.stderr b/tests/misc/projects/Issue6796/pretty-fail.hxml.stderr index 2b8127e3ae3..5097a920510 100644 --- a/tests/misc/projects/Issue6796/pretty-fail.hxml.stderr +++ b/tests/misc/projects/Issue6796/pretty-fail.hxml.stderr @@ -3,5 +3,6 @@ 3 | Sys.println(main["foo"]); | ^^^^ | Array access is not allowed on () -> Unknown<0> - | For function argument 'v' + + | For function argument 'v' diff --git a/tests/misc/projects/Issue8283/compile-fail.hxml.stderr b/tests/misc/projects/Issue8283/compile-fail.hxml.stderr index 8bf3f537bbd..f46c023efef 100644 --- a/tests/misc/projects/Issue8283/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue8283/compile-fail.hxml.stderr @@ -1,4 +1,3 @@ Main.hx:9: characters 35-48 : Arrays of mixed types are only allowed if the type is forced to Array -Main.hx:9: characters 35-48 : Arrays of mixed types are only allowed if the type is forced to Array Main.hx:9: characters 35-48 : String should be Int Main.hx:9: characters 35-48 : ... For optional function argument 'arr' \ No newline at end of file diff --git a/tests/misc/projects/Issue8828/compile2-fail.hxml.stderr b/tests/misc/projects/Issue8828/compile2-fail.hxml.stderr index b30c5242051..f18a0e5e9b9 100644 --- a/tests/misc/projects/Issue8828/compile2-fail.hxml.stderr +++ b/tests/misc/projects/Issue8828/compile2-fail.hxml.stderr @@ -1,2 +1,2 @@ Main2.hx:2: characters 9-16 : Conflicting access modifier public -Main2.hx:2: characters 2-8 : Conflicts with this \ No newline at end of file +Main2.hx:2: characters 2-8 : ... Conflicts with this diff --git a/tests/misc/projects/Issue8828/compile3-fail.hxml.stderr b/tests/misc/projects/Issue8828/compile3-fail.hxml.stderr index 847f1700f19..96c33d245d0 100644 --- a/tests/misc/projects/Issue8828/compile3-fail.hxml.stderr +++ b/tests/misc/projects/Issue8828/compile3-fail.hxml.stderr @@ -1,2 +1,2 @@ Main3.hx:2: characters 10-16 : Conflicting access modifier private -Main3.hx:2: characters 2-9 : Conflicts with this \ No newline at end of file +Main3.hx:2: characters 2-9 : ... Conflicts with this diff --git a/tests/misc/projects/Issue9619/missing-abstract-on-class/compile-fail.hxml.stderr b/tests/misc/projects/Issue9619/missing-abstract-on-class/compile-fail.hxml.stderr index bb97f5edd14..c110d130f64 100644 --- a/tests/misc/projects/Issue9619/missing-abstract-on-class/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue9619/missing-abstract-on-class/compile-fail.hxml.stderr @@ -1,2 +1,2 @@ Main.hx:1: characters 7-11 : This class should be declared abstract because it has at least one abstract field -Main.hx:6: characters 20-36 : First abstract field was here \ No newline at end of file +Main.hx:6: characters 20-36 : ... First abstract field was here diff --git a/tests/misc/projects/IssueXXXXX/Main.hx b/tests/misc/projects/IssueXXXXX/Main.hx new file mode 100644 index 00000000000..41b01c72fd2 --- /dev/null +++ b/tests/misc/projects/IssueXXXXX/Main.hx @@ -0,0 +1,11 @@ +class Main { + static function main() { + foo(); + } + + static macro function foo() { + return macro { + var a:String = 42; + }; + } +} diff --git a/tests/misc/projects/IssueXXXXX/Main2.hx b/tests/misc/projects/IssueXXXXX/Main2.hx new file mode 100644 index 00000000000..c1798fc695e --- /dev/null +++ b/tests/misc/projects/IssueXXXXX/Main2.hx @@ -0,0 +1,19 @@ +import haxe.Constraints; + +class Main2 { + static function main() {} +} + +class GenericTestVoid>)> { + public function new(){} + + public function someTask():Void { + var instance:T = getInstance("foo"); + } + + @:generic + private function getInstanceVoid>)>(arg:String):S { + return new S(arg); + } +} + diff --git a/tests/misc/projects/IssueXXXXX/Main3.hx b/tests/misc/projects/IssueXXXXX/Main3.hx new file mode 100644 index 00000000000..b13e797f396 --- /dev/null +++ b/tests/misc/projects/IssueXXXXX/Main3.hx @@ -0,0 +1,22 @@ +class Main3 extends Base { + public static function main() {} + override function foo(a) ""; +} + +private class Base { + function foo(a:Int):String return ""; +} + +private class Foo { + public public var foo:String; + public private var bar:String; +} + +typedef Bar = { + var bar:String; +} + +typedef Baz = Bar & { + var bar:Int; + var baz:Int; +} diff --git a/tests/misc/projects/IssueXXXXX/compile-fail.hxml b/tests/misc/projects/IssueXXXXX/compile-fail.hxml new file mode 100644 index 00000000000..42409e72918 --- /dev/null +++ b/tests/misc/projects/IssueXXXXX/compile-fail.hxml @@ -0,0 +1 @@ +-main Main diff --git a/tests/misc/projects/IssueXXXXX/compile-fail.hxml.stderr b/tests/misc/projects/IssueXXXXX/compile-fail.hxml.stderr new file mode 100644 index 00000000000..a244732e43f --- /dev/null +++ b/tests/misc/projects/IssueXXXXX/compile-fail.hxml.stderr @@ -0,0 +1,2 @@ +Main.hx:8: characters 4-22 : Int should be String +Main.hx:3: characters 3-8 : ... Called from macro here diff --git a/tests/misc/projects/IssueXXXXX/compile2-fail.hxml b/tests/misc/projects/IssueXXXXX/compile2-fail.hxml new file mode 100644 index 00000000000..27d6e39ab72 --- /dev/null +++ b/tests/misc/projects/IssueXXXXX/compile2-fail.hxml @@ -0,0 +1 @@ +-main Main2 diff --git a/tests/misc/projects/IssueXXXXX/compile2-fail.hxml.stderr b/tests/misc/projects/IssueXXXXX/compile2-fail.hxml.stderr new file mode 100644 index 00000000000..b98614cb65c --- /dev/null +++ b/tests/misc/projects/IssueXXXXX/compile2-fail.hxml.stderr @@ -0,0 +1,4 @@ +Main.hx:8: characters 4-22 : Int should be String +Main.hx:3: characters 3-8 : ... Called from macro here +Main2.hx:16: characters 10-20 : Only generic type parameters can be constructed +Main2.hx:11: characters 20-38 : ... While specializing this call diff --git a/tests/misc/projects/IssueXXXXX/compile3-fail.hxml b/tests/misc/projects/IssueXXXXX/compile3-fail.hxml new file mode 100644 index 00000000000..83eea6fa92b --- /dev/null +++ b/tests/misc/projects/IssueXXXXX/compile3-fail.hxml @@ -0,0 +1 @@ +-main Main3 diff --git a/tests/misc/projects/IssueXXXXX/compile3-fail.hxml.stderr b/tests/misc/projects/IssueXXXXX/compile3-fail.hxml.stderr new file mode 100644 index 00000000000..7c73d740070 --- /dev/null +++ b/tests/misc/projects/IssueXXXXX/compile3-fail.hxml.stderr @@ -0,0 +1,12 @@ +Main3.hx:11: characters 9-15 : Duplicate access modifier public +Main3.hx:11: characters 2-8 : ... Previously defined here +Main3.hx:12: characters 9-16 : Conflicting access modifier private +Main3.hx:12: characters 2-8 : ... Conflicts with this +Main3.hx:3: characters 20-23 : Field foo overrides parent class with different or incomplete type +Main3.hx:7: characters 11-14 : ... Base field is defined here +Main3.hx:3: characters 20-23 : ... error: Void should be String +Main3.hx:3: characters 20-23 : ... have: (...) -> Void +Main3.hx:3: characters 20-23 : ... want: (...) -> String +Main3.hx:19: lines 19-22 : Cannot redefine field bar with different type +Main3.hx:20: characters 2-14 : ... First type was Int +Main3.hx:16: characters 2-17 : ... Second type was String diff --git a/tests/unit/src/unit/issues/Issue3714.hx b/tests/unit/src/unit/issues/Issue3714.hx index bc6a47a9e0e..067849b196d 100644 --- a/tests/unit/src/unit/issues/Issue3714.hx +++ b/tests/unit/src/unit/issues/Issue3714.hx @@ -10,6 +10,6 @@ class Issue3714 extends Test { eq(unit.HelperMacros.typeErrorText(A.f), "Cannot access private field f"); eq(unit.HelperMacros.typeErrorText(@:privateAccess A.f), null); eq(unit.HelperMacros.typeErrorText(@:privateAccess A.f(A.a)), null); - eq(unit.HelperMacros.typeErrorText(@:privateAccess A.f(@:noPrivateAccess A.a)), "Cannot access private field a\nFor function argument 'a'"); + eq(unit.HelperMacros.typeErrorText(@:privateAccess A.f(@:noPrivateAccess A.a)), "Cannot access private field a\n... For function argument 'a'"); } } From e3a417aa7a15dbbcdb05970645deb6f5f9853a11 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Tue, 12 Mar 2024 12:41:19 +0100 Subject: [PATCH 19/49] [tests] rename test folder for 11595 --- tests/misc/projects/{IssueXXXXX => Issue11595}/Main.hx | 0 tests/misc/projects/{IssueXXXXX => Issue11595}/Main2.hx | 0 tests/misc/projects/{IssueXXXXX => Issue11595}/Main3.hx | 0 tests/misc/projects/{IssueXXXXX => Issue11595}/compile-fail.hxml | 0 .../projects/{IssueXXXXX => Issue11595}/compile-fail.hxml.stderr | 0 tests/misc/projects/{IssueXXXXX => Issue11595}/compile2-fail.hxml | 0 .../projects/{IssueXXXXX => Issue11595}/compile2-fail.hxml.stderr | 0 tests/misc/projects/{IssueXXXXX => Issue11595}/compile3-fail.hxml | 0 .../projects/{IssueXXXXX => Issue11595}/compile3-fail.hxml.stderr | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename tests/misc/projects/{IssueXXXXX => Issue11595}/Main.hx (100%) rename tests/misc/projects/{IssueXXXXX => Issue11595}/Main2.hx (100%) rename tests/misc/projects/{IssueXXXXX => Issue11595}/Main3.hx (100%) rename tests/misc/projects/{IssueXXXXX => Issue11595}/compile-fail.hxml (100%) rename tests/misc/projects/{IssueXXXXX => Issue11595}/compile-fail.hxml.stderr (100%) rename tests/misc/projects/{IssueXXXXX => Issue11595}/compile2-fail.hxml (100%) rename tests/misc/projects/{IssueXXXXX => Issue11595}/compile2-fail.hxml.stderr (100%) rename tests/misc/projects/{IssueXXXXX => Issue11595}/compile3-fail.hxml (100%) rename tests/misc/projects/{IssueXXXXX => Issue11595}/compile3-fail.hxml.stderr (100%) diff --git a/tests/misc/projects/IssueXXXXX/Main.hx b/tests/misc/projects/Issue11595/Main.hx similarity index 100% rename from tests/misc/projects/IssueXXXXX/Main.hx rename to tests/misc/projects/Issue11595/Main.hx diff --git a/tests/misc/projects/IssueXXXXX/Main2.hx b/tests/misc/projects/Issue11595/Main2.hx similarity index 100% rename from tests/misc/projects/IssueXXXXX/Main2.hx rename to tests/misc/projects/Issue11595/Main2.hx diff --git a/tests/misc/projects/IssueXXXXX/Main3.hx b/tests/misc/projects/Issue11595/Main3.hx similarity index 100% rename from tests/misc/projects/IssueXXXXX/Main3.hx rename to tests/misc/projects/Issue11595/Main3.hx diff --git a/tests/misc/projects/IssueXXXXX/compile-fail.hxml b/tests/misc/projects/Issue11595/compile-fail.hxml similarity index 100% rename from tests/misc/projects/IssueXXXXX/compile-fail.hxml rename to tests/misc/projects/Issue11595/compile-fail.hxml diff --git a/tests/misc/projects/IssueXXXXX/compile-fail.hxml.stderr b/tests/misc/projects/Issue11595/compile-fail.hxml.stderr similarity index 100% rename from tests/misc/projects/IssueXXXXX/compile-fail.hxml.stderr rename to tests/misc/projects/Issue11595/compile-fail.hxml.stderr diff --git a/tests/misc/projects/IssueXXXXX/compile2-fail.hxml b/tests/misc/projects/Issue11595/compile2-fail.hxml similarity index 100% rename from tests/misc/projects/IssueXXXXX/compile2-fail.hxml rename to tests/misc/projects/Issue11595/compile2-fail.hxml diff --git a/tests/misc/projects/IssueXXXXX/compile2-fail.hxml.stderr b/tests/misc/projects/Issue11595/compile2-fail.hxml.stderr similarity index 100% rename from tests/misc/projects/IssueXXXXX/compile2-fail.hxml.stderr rename to tests/misc/projects/Issue11595/compile2-fail.hxml.stderr diff --git a/tests/misc/projects/IssueXXXXX/compile3-fail.hxml b/tests/misc/projects/Issue11595/compile3-fail.hxml similarity index 100% rename from tests/misc/projects/IssueXXXXX/compile3-fail.hxml rename to tests/misc/projects/Issue11595/compile3-fail.hxml diff --git a/tests/misc/projects/IssueXXXXX/compile3-fail.hxml.stderr b/tests/misc/projects/Issue11595/compile3-fail.hxml.stderr similarity index 100% rename from tests/misc/projects/IssueXXXXX/compile3-fail.hxml.stderr rename to tests/misc/projects/Issue11595/compile3-fail.hxml.stderr From 3297a0bae2ab5bee798ba43b0dd8102965e1b55d Mon Sep 17 00:00:00 2001 From: Ian Date: Mon, 18 Mar 2024 02:26:54 -0400 Subject: [PATCH 20/49] Only write default Connection header to HTTP requests if needed (#11604) Currently sys/Http writes "Connection: Close" to all requests, but this should not be done if, for example, a given request includes a "Connection: Keep-Alive" header. --- std/sys/Http.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/std/sys/Http.hx b/std/sys/Http.hx index a4fc7f10a7b..d610b479c58 100644 --- a/std/sys/Http.hx +++ b/std/sys/Http.hx @@ -223,7 +223,8 @@ class Http extends haxe.http.HttpBase { else b.writeString("Content-Length: " + uri.length + "\r\n"); } - b.writeString("Connection: close\r\n"); + if( !Lambda.exists(headers, function(h) return h.name == "Connection") ) + b.writeString("Connection: close\r\n"); for (h in headers) { b.writeString(h.name); b.writeString(": "); From 00e2a93ebe8dd2239b05bbc171a2d475f8a0a2ec Mon Sep 17 00:00:00 2001 From: Ryan Cleven Date: Wed, 13 Mar 2024 21:58:09 -0700 Subject: [PATCH 21/49] Fixed hbytes compare --- src/generators/hl2c.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/generators/hl2c.ml b/src/generators/hl2c.ml index 035b9838be5..550db7090fb 100644 --- a/src/generators/hl2c.ml +++ b/src/generators/hl2c.ml @@ -744,6 +744,8 @@ let generate_function ctx f = match rtype a, rtype b with | (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64), (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64) -> phys_compare() + | HBytes, HBytes -> + phys_compare() | HType, HType -> sexpr "if( hl_same_type(%s,%s) %s 0 ) {} else goto %s" (reg a) (reg b) (s_comp op) (label d) | HNull t, HNull _ -> From 790656da1d9bb6903adb9dd41ebc7edae11ba15f Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Sat, 10 Feb 2024 16:38:47 +0100 Subject: [PATCH 22/49] add HArray,HArray case to compare function --- src/generators/hl2c.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generators/hl2c.ml b/src/generators/hl2c.ml index 550db7090fb..20b920a29cd 100644 --- a/src/generators/hl2c.ml +++ b/src/generators/hl2c.ml @@ -744,7 +744,7 @@ let generate_function ctx f = match rtype a, rtype b with | (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64), (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64) -> phys_compare() - | HBytes, HBytes -> + | HBytes, HBytes | HArray,HArray -> phys_compare() | HType, HType -> sexpr "if( hl_same_type(%s,%s) %s 0 ) {} else goto %s" (reg a) (reg b) (s_comp op) (label d) From c2724bfdda87ab037d7025aeca3e353c7fd9ddfa Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Tue, 19 Mar 2024 08:59:43 +0100 Subject: [PATCH 23/49] [ci] check target branch for PRs --- .github/workflows/target.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/target.yml diff --git a/.github/workflows/target.yml b/.github/workflows/target.yml new file mode 100644 index 00000000000..b167780548b --- /dev/null +++ b/.github/workflows/target.yml @@ -0,0 +1,19 @@ +name: Check pull request target branch +on: + pull_request_target: + types: + - opened + - reopened + - synchronize + - edited +jobs: + check-branches: + runs-on: ubuntu-latest + steps: + - name: Check branches + run: | + if [ ${{ github.base_ref }} != "development" ]; then + echo "Merge requests should target `development`." + exit 1 + fi + From 8d0f87d2ca06585892bbba9fcd34bcb66f0ca031 Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Tue, 19 Mar 2024 10:13:39 +0100 Subject: [PATCH 24/49] [tests] hlc NativeArray Bytes comparison (#11614) --- tests/unit/src/unit/issues/Issue11468.hx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/unit/src/unit/issues/Issue11468.hx diff --git a/tests/unit/src/unit/issues/Issue11468.hx b/tests/unit/src/unit/issues/Issue11468.hx new file mode 100644 index 00000000000..6bbe01e9d63 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11468.hx @@ -0,0 +1,19 @@ +package unit.issues; +import unit.Test; + +class Issue11468 extends Test { + + #if hl + function test() { + var m = new Map>(); + t(m.get(0) == null); + var arr = new hl.NativeArray(1); + f(arr == null); + + var b1 = new hl.Bytes(0); + t(b1 == null); + var b2 = new hl.Bytes(1); + f(b2 == null); + } + #end +} \ No newline at end of file From 3b0c8f4054374de4289df2ce97c3b524759fa59a Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Wed, 20 Mar 2024 10:47:45 +0100 Subject: [PATCH 25/49] [hl] Rework Null comparison for spec/alloc (#11612) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [tests] import some ops tests from genjvm * echo lines on flash unit tests * Something that pass the spec test * Add jnull when compare nullnum with num * Improve syntax and fun name * Remove the use of common_type_safe_number * Also skip todyn for Null/Bool eq * Revert TestOps as Flash fail * Revert "Revert TestOps as Flash fail" This reverts commit f82a51c29599ed69b9ec7d5726d97f0cf585b16d. * Do not do testNadakoOps for flash --------- Co-authored-by: Simon Krajewski Co-authored-by: Aurel Bílý --- src/generators/genhl.ml | 193 +++++++++++++++++++------------ src/generators/hlcode.ml | 8 +- tests/unit/src/unit/TestOps.hx | 203 +++++++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+), 73 deletions(-) diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index 0c26dd72ed6..906269742f1 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -951,34 +951,39 @@ let write_mem ctx bytes index t r = | _ -> die "" __LOC__ +let common_type_number ctx t1 t2 p = + if t1 == t2 then t1 else + match t1, t2 with + | HUI8, (HUI16 | HI32 | HI64 | HF32 | HF64) -> t2 + | HUI16, (HI32 | HI64 | HF32 | HF64) -> t2 + | (HI32 | HI64), HF32 -> t2 (* possible loss of precision *) + | (HI32 | HI64 | HF32), HF64 -> t2 + | (HUI8|HUI16|HI32|HI64|HF32|HF64), (HUI8|HUI16|HI32|HI64|HF32|HF64) -> t1 + | _ -> + die "" __LOC__ + let common_type ctx e1 e2 for_eq p = let t1 = to_type ctx e1.etype in let t2 = to_type ctx e2.etype in - let rec loop t1 t2 = - if t1 == t2 then t1 else - match t1, t2 with - | HUI8, (HUI16 | HI32 | HI64 | HF32 | HF64) -> t2 - | HUI16, (HI32 | HI64 | HF32 | HF64) -> t2 - | (HI32 | HI64), HF32 -> t2 (* possible loss of precision *) - | (HI32 | HI64 | HF32), HF64 -> t2 - | (HUI8|HUI16|HI32|HI64|HF32|HF64), (HUI8|HUI16|HI32|HI64|HF32|HF64) -> t1 - | (HUI8|HUI16|HI32|HI64|HF32|HF64), (HNull t2) -> if for_eq then HNull (loop t1 t2) else loop t1 t2 - | (HNull t1), (HUI8|HUI16|HI32|HI64|HF32|HF64) -> if for_eq then HNull (loop t1 t2) else loop t1 t2 - | (HNull t1), (HNull t2) -> if for_eq then HNull (loop t1 t2) else loop t1 t2 - | HDyn, (HUI8|HUI16|HI32|HI64|HF32|HF64) -> HF64 - | (HUI8|HUI16|HI32|HI64|HF32|HF64), HDyn -> HF64 - | HDyn, _ -> HDyn - | _, HDyn -> HDyn - | _ when for_eq && safe_cast t1 t2 -> t2 - | _ when for_eq && safe_cast t2 t1 -> t1 - | HBool, HNull HBool when for_eq -> t2 - | HNull HBool, HBool when for_eq -> t1 - | HObj _, HVirtual _ | HVirtual _, HObj _ | HVirtual _ , HVirtual _ -> HDyn - | HFun _, HFun _ -> HDyn - | _ -> - abort ("Don't know how to compare " ^ tstr t1 ^ " and " ^ tstr t2) p - in - loop t1 t2 + if t1 == t2 then t1 else + match t1, t2 with + | (HUI8|HUI16|HI32|HI64|HF32|HF64), (HUI8|HUI16|HI32|HI64|HF32|HF64) -> common_type_number ctx t1 t2 p + | (HUI8|HUI16|HI32|HI64|HF32|HF64 as t1), (HNull t2) + | (HNull t1), (HUI8|HUI16|HI32|HI64|HF32|HF64 as t2) + | (HNull t1), (HNull t2) + -> if for_eq then HNull (common_type_number ctx t1 t2 p) else common_type_number ctx t1 t2 p + | HDyn, (HUI8|HUI16|HI32|HI64|HF32|HF64) -> HF64 + | (HUI8|HUI16|HI32|HI64|HF32|HF64), HDyn -> HF64 + | HDyn, _ -> HDyn + | _, HDyn -> HDyn + | _ when for_eq && safe_cast t1 t2 -> t2 + | _ when for_eq && safe_cast t2 t1 -> t1 + | HBool, HNull HBool when for_eq -> t2 + | HNull HBool, HBool when for_eq -> t1 + | HObj _, HVirtual _ | HVirtual _, HObj _ | HVirtual _ , HVirtual _ -> HDyn + | HFun _, HFun _ -> HDyn + | _ -> + abort ("Can't find common type " ^ tstr t1 ^ " and " ^ tstr t2) p let captured_index ctx v = if not (has_var_flag v VCaptured) then None else try Some (PMap.find v.v_id ctx.m.mcaptured.c_map) with Not_found -> None @@ -1479,24 +1484,92 @@ and jump_expr ctx e jcond = jump ctx (fun i -> OJAlways i) else (fun i -> ()) - | TBinop (OpEq | OpNotEq | OpGt | OpGte | OpLt | OpLte as jop, e1, e2) -> - let t = common_type ctx e1 e2 (match jop with OpEq | OpNotEq -> true | _ -> false) e.epos in - let r1 = eval_to ctx e1 t in - hold ctx r1; - let r2 = eval_to ctx e2 t in - free ctx r1; - let unsigned = unsigned_op e1 e2 in - jump ctx (fun i -> - let lt a b = if unsigned then OJULt (a,b,i) else if not jcond && is_float t then OJNotGte (a,b,i) else OJSLt (a,b,i) in - let gte a b = if unsigned then OJUGte (a,b,i) else if not jcond && is_float t then OJNotLt (a,b,i) else OJSGte (a,b,i) in + | TBinop (OpEq | OpNotEq as jop, e1, e2) -> + let jumpeq r1 r2 = jump ctx (fun i -> match jop with | OpEq -> if jcond then OJEq (r1,r2,i) else OJNotEq (r1,r2,i) | OpNotEq -> if jcond then OJNotEq (r1,r2,i) else OJEq (r1,r2,i) - | OpGt -> if jcond then lt r2 r1 else gte r2 r1 - | OpGte -> if jcond then gte r1 r2 else lt r1 r2 - | OpLt -> if jcond then lt r1 r2 else gte r1 r2 - | OpLte -> if jcond then gte r2 r1 else lt r2 r1 | _ -> die "" __LOC__ + ) in + let t1 = to_type ctx e1.etype in + let t2 = to_type ctx e2.etype in + (match t1, t2 with + | HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2) + | (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2) + | HNull (HBool as ti1), (HBool as ti2) + | (HBool as ti1), HNull (HBool as ti2) + -> + let t1,t2,e1,e2 = if is_nullt t2 then t2,t1,e2,e1 else t1,t2,e1,e2 in + let r1 = eval_expr ctx e1 in + hold ctx r1; + let jnull = if is_nullt t1 then jump ctx (fun i -> OJNull (r1, i)) else (fun i -> ()) in + let t = common_type_number ctx ti1 ti2 e.epos in (* HBool has t==ti1==ti2 *) + let a = cast_to ctx r1 t e1.epos in + hold ctx a; + let b = eval_to ctx e2 t in + free ctx a; + free ctx r1; + let j = jumpeq a b in + if jcond then (jnull();); + (fun() -> if not jcond then (jnull();); j()); + | _ -> + let t = common_type ctx e1 e2 true e.epos in + let a = eval_to ctx e1 t in + hold ctx a; + let b = eval_to ctx e2 t in + free ctx a; + let j = jumpeq a b in + (fun() -> j()); + ) + | TBinop (OpGt | OpGte | OpLt | OpLte as jop, e1, e2) -> + let t1 = to_type ctx e1.etype in + let t2 = to_type ctx e2.etype in + let unsigned = unsigned_op e1 e2 in + let jumpcmp t r1 r2 = jump ctx (fun i -> + let lt a b = if unsigned then OJULt (a,b,i) else if not jcond && is_float t then OJNotGte (a,b,i) else OJSLt (a,b,i) in + let gte a b = if unsigned then OJUGte (a,b,i) else if not jcond && is_float t then OJNotLt (a,b,i) else OJSGte (a,b,i) in + match jop with + | OpGt -> if jcond then lt r2 r1 else gte r2 r1 + | OpGte -> if jcond then gte r1 r2 else lt r1 r2 + | OpLt -> if jcond then lt r1 r2 else gte r1 r2 + | OpLte -> if jcond then gte r2 r1 else lt r2 r1 + | _ -> die "" __LOC__ + ) in + (match t1, t2 with + | (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2) + | HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2) + | (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2) + | HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2) + -> + let r1 = eval_expr ctx e1 in + hold ctx r1; + let jnull1 = if is_nullt t1 then jump ctx (fun i -> OJNull (r1, i)) else (fun i -> ()) in + let r2 = eval_expr ctx e2 in + hold ctx r2; + let jnull2 = if is_nullt t2 then jump ctx (fun i -> OJNull (r2, i)) else (fun i -> ()) in + let t = common_type_number ctx ti1 ti2 e.epos in + let a = cast_to ctx r1 t e1.epos in + hold ctx a; + let b = cast_to ctx r2 t e2.epos in + free ctx a; + free ctx r1; + free ctx r2; + let j = jumpcmp t a b in + if jcond then (jnull1(); jnull2();); + (fun() -> if not jcond then (jnull1(); jnull2();); j()); + | HObj { pname = "String" }, HObj { pname = "String" } + | HDyn, _ + | _, HDyn + -> + let t = common_type ctx e1 e2 false e.epos in + let a = eval_to ctx e1 t in + hold ctx a; + let b = eval_to ctx e2 t in + free ctx a; + let j = jumpcmp t a b in + (fun() -> j()); + | _ -> + abort ("Don't know how to compare " ^ tstr t1 ^ " and " ^ tstr t2) e.epos ) | TBinop (OpBoolAnd, e1, e2) -> let j = jump_expr ctx e1 false in @@ -2341,23 +2414,9 @@ and eval_expr ctx e = jexit()); out | TBinop (bop, e1, e2) -> - let is_unsigned() = unsigned_op e1 e2 in - let boolop r f = - let j = jump ctx f in - op ctx (OBool (r,false)); - op ctx (OJAlways 1); - j(); - op ctx (OBool (r, true)); - in - let binop r a b = + let arithbinop r a b = let rec loop bop = match bop with - | OpLte -> boolop r (fun d -> if is_unsigned() then OJUGte (b,a,d) else OJSLte (a,b,d)) - | OpGt -> boolop r (fun d -> if is_unsigned() then OJULt (b,a,d) else OJSGt (a,b,d)) - | OpGte -> boolop r (fun d -> if is_unsigned() then OJUGte (a,b,d) else OJSGte (a,b,d)) - | OpLt -> boolop r (fun d -> if is_unsigned() then OJULt (a,b,d) else OJSLt (a,b,d)) - | OpEq -> boolop r (fun d -> OJEq (a,b,d)) - | OpNotEq -> boolop r (fun d -> OJNotEq (a,b,d)) | OpAdd -> (match rtype ctx r with | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 -> @@ -2404,23 +2463,13 @@ and eval_expr ctx e = loop bop in (match bop with - | OpLte | OpGt | OpGte | OpLt -> + | OpLte | OpGt | OpGte | OpLt | OpEq | OpNotEq -> let r = alloc_tmp ctx HBool in - let t = common_type ctx e1 e2 false e.epos in - let a = eval_to ctx e1 t in - hold ctx a; - let b = eval_to ctx e2 t in - free ctx a; - binop r a b; - r - | OpEq | OpNotEq -> - let r = alloc_tmp ctx HBool in - let t = common_type ctx e1 e2 true e.epos in - let a = eval_to ctx e1 t in - hold ctx a; - let b = eval_to ctx e2 t in - free ctx a; - binop r a b; + let j = jump_expr ctx e false in + op ctx (OBool (r, true)); + op ctx (OJAlways 1); + j(); + op ctx (OBool (r, false)); r | OpAdd | OpSub | OpMult | OpDiv | OpMod | OpShl | OpShr | OpUShr | OpAnd | OpOr | OpXor -> let t = (match to_type ctx e.etype with HNull t -> t | t -> t) in @@ -2437,7 +2486,7 @@ and eval_expr ctx e = hold ctx a; let b = eval e2 in free ctx a; - binop r a b; + arithbinop r a b; r | OpAssign -> let value() = eval_to ctx e2 (real_type ctx e1) in @@ -2555,7 +2604,7 @@ and eval_expr ctx e = hold ctx r; let b = if bop = OpAdd && is_string (rtype ctx r) then to_string ctx (eval_expr ctx e2) e2.epos else eval_to ctx e2 (rtype ctx r) in free ctx r; - binop r r b; + arithbinop r r b; r)) | OpInterval | OpArrow | OpIn | OpNullCoal -> die "" __LOC__) diff --git a/src/generators/hlcode.ml b/src/generators/hlcode.ml index 1636c2546db..889015c6795 100644 --- a/src/generators/hlcode.ml +++ b/src/generators/hlcode.ml @@ -45,7 +45,7 @@ type ttype = | HDynObj | HAbstract of string * string index | HEnum of enum_proto - | HNull of ttype + | HNull of ttype (* for not nullable type only *) | HMethod of ttype list * ttype | HStruct of class_proto | HPacked of ttype @@ -277,6 +277,12 @@ let is_number = function | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 -> true | _ -> false +let is_nullt = function + | HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64) -> true + | HNull HBool -> true + | HNull _ -> Globals.die "" __LOC__ + | _ -> false + (* does the runtime value carry its type *) diff --git a/tests/unit/src/unit/TestOps.hx b/tests/unit/src/unit/TestOps.hx index 5893cb068b7..474c1aff894 100644 --- a/tests/unit/src/unit/TestOps.hx +++ b/tests/unit/src/unit/TestOps.hx @@ -101,4 +101,207 @@ class TestOps extends Test { static function getA() return { a:1 }; + #if target.static + + function testNullOps() { + var a:Null = 10; + // arithmetic + eq(9, a - 1); + eq(20, a * 2); + eq(5., a / 2); // careful with Float comparison... + eq(1, a % 3); + + // bit + eq(20, a << 1); + eq(5, a >> 1); + eq(5, a >>> 1); + eq(10, a & 15); + eq(15, a | 15); + eq(2, a ^ 8); + + // unary + eq(-10, -a); + eq(-11, ~a); + + // boolean + var b:Null = true; + eq(false, !b); + eq(false, b && falseValue); + eq(true, b && trueValue); + eq(true, b || falseValue); + eq(true, b || trueValue); + + b = false; + eq(true, !b); + eq(false, b && falseValue); + eq(false, b && trueValue); + eq(false, b || falseValue); + eq(true, b || trueValue); + + eq(true, a > 5); + eq(true, a >= 5); + eq(false, a < 5); + eq(false, a <= 5); + eq(true, a != 5); + eq(false, a != 10); + + eq(false, 0 > a); + eq(false, 0 >= a); + eq(true, 0 < a); + eq(true, 0 <= a); + eq(true, 0 != a); + eq(false, 0 == a); + + var minusA:Null = -10; + eq(true, 0 > minusA); + eq(true, 0 >= minusA); + eq(false, 0 < minusA); + eq(false, 0 <= minusA); + eq(true, 0 != minusA); + eq(false, 0 == minusA); + } + + #if !flash // Will not fix for flash + + function testNadakoOps() { + // bool + var nullBool:Null = null; + + t(null == nullBool); + t(nullBool == null); + f(false == nullBool); + f(nullBool == false); + t(false != nullBool); + t(nullBool != false); + + // int + var nullInt:Null = null; + + t(null == nullInt); + t(nullInt == null); + f(0 == nullInt); + f(nullInt == 0); + t(0 != nullInt); + t(nullInt != 0); + + f(0 > nullInt); + f(0 >= nullInt); + f(0 < nullInt); + f(0 <= nullInt); + + f(nullInt > 0); + f(nullInt >= 0); + f(nullInt < 0); + f(nullInt <= 0); + + f(1 > nullInt); + f(1 >= nullInt); + f(1 < nullInt); + f(1 <= nullInt); + + f(nullInt > 1); + f(nullInt >= 1); + f(nullInt < 1); + f(nullInt <= 1); + + f(-1 > nullInt); + f(-1 >= nullInt); + f(-1 < nullInt); + f(-1 <= nullInt); + + f(nullInt > -1); + f(nullInt >= -1); + f(nullInt < -1); + f(nullInt <= -1); + + // // float + var nullFloat:Null = null; + + t(null == nullFloat); + t(nullFloat == null); + f(0. == nullFloat); + f(nullFloat == 0.); + t(0. != nullFloat); + t(nullFloat != 0.); + + f(0. > nullFloat); + f(0. >= nullFloat); + f(0. < nullFloat); + f(0. <= nullFloat); + + f(nullFloat > 0.); + f(nullFloat >= 0.); + f(nullFloat < 0.); + f(nullFloat <= 0.); + + f(1. > nullFloat); + f(1. >= nullFloat); + f(1. < nullFloat); + f(1. <= nullFloat); + + f(nullFloat > 1.); + f(nullFloat >= 1.); + f(nullFloat < 1.); + f(nullFloat <= 1.); + + f(-1. > nullFloat); + f(-1. >= nullFloat); + f(-1. < nullFloat); + f(-1. <= nullFloat); + + f(nullFloat > -1.); + f(nullFloat >= -1.); + f(nullFloat < -1.); + f(nullFloat <= -1.); + } + + #end + + function testDynamicOps() { + var a:Dynamic = 10; + // arithmetic + eq(9., a - 1); + eq(20., a * 2); + feq(5., a / 2); + feq(1., a % 3); + + // bit + eq(20, a << 1); + eq(5, a >> 1); + eq(5, a >>> 1); + eq(10, a & 15); + eq(15, a | 15); + eq(2, a ^ 8); + + // unary + eq(-10., -a); + eq(-11, ~a); + + // boolean + var b:Dynamic = true; + eq(false, !b); + eq(false, b && falseValue); + eq(true, b && trueValue); + eq(true, b || falseValue); + eq(true, b || trueValue); + + b = false; + eq(true, !b); + eq(false, b && falseValue); + eq(false, b && trueValue); + eq(false, b || falseValue); + eq(true, b || trueValue); + + eq(true, a > 5); + eq(true, a >= 5); + eq(false, a < 5); + eq(false, a <= 5); + eq(true, a != 5); + eq(false, a != 10); + } + + static var trueValue = true; + static var falseValue = false; + + #end } From 1423a5f2ddf4f2976e15340eaf42889ddfc3ada6 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 21 Mar 2024 09:55:23 +0100 Subject: [PATCH 26/49] Add -D fail-fast (#11609) * Add -D fail-fast * [tests] add some tests for -D fast-fail * [tests] more tests for -D fast-fail * [tests] fix file names * Keep same signature with or without -D fail-fast --- src-json/define.json | 5 +++++ src/compiler/compilationContext.ml | 16 +++++++++++---- src/compiler/compiler.ml | 5 +++-- src/compiler/messageReporting.ml | 9 +++++++-- src/context/common.ml | 1 + src/core/define.ml | 2 +- .../projects/Issue6065/compile-fast-fail.hxml | 2 ++ .../Issue6065/compile-fast-fail.hxml.stderr | 8 ++++++++ .../projects/Issue6065/indent-fast-fail.hxml | 2 ++ .../Issue6065/indent-fast-fail.hxml.stderr | 7 +++++++ .../projects/Issue6065/pretty-fast-fail.hxml | 2 ++ .../Issue6065/pretty-fast-fail.hxml.stderr | 20 +++++++++++++++++++ .../projects/Issue8019/compile-fast-fail.hxml | 2 ++ .../Issue8019/compile-fast-fail.hxml.stderr | 2 ++ .../Issue8019/compile3-fast-fail.hxml | 2 ++ .../Issue8019/compile3-fast-fail.hxml.stderr | 1 + .../projects/issue5002/compile-fast-fail.hxml | 2 ++ .../issue5002/compile-fast-fail.hxml.stderr | 1 + .../issue5002/compile2-fast-fail.hxml | 2 ++ .../issue5002/compile2-fast-fail.hxml.stderr | 1 + .../issue5002/compile3-fast-fail.hxml | 2 ++ .../issue5002/compile3-fast-fail.hxml.stderr | 1 + .../issue5002/compile4-fast-fail.hxml | 2 ++ .../issue5002/compile4-fast-fail.hxml.stderr | 1 + 24 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 tests/misc/projects/Issue6065/compile-fast-fail.hxml create mode 100644 tests/misc/projects/Issue6065/compile-fast-fail.hxml.stderr create mode 100644 tests/misc/projects/Issue6065/indent-fast-fail.hxml create mode 100644 tests/misc/projects/Issue6065/indent-fast-fail.hxml.stderr create mode 100644 tests/misc/projects/Issue6065/pretty-fast-fail.hxml create mode 100644 tests/misc/projects/Issue6065/pretty-fast-fail.hxml.stderr create mode 100644 tests/misc/projects/Issue8019/compile-fast-fail.hxml create mode 100644 tests/misc/projects/Issue8019/compile-fast-fail.hxml.stderr create mode 100644 tests/misc/projects/Issue8019/compile3-fast-fail.hxml create mode 100644 tests/misc/projects/Issue8019/compile3-fast-fail.hxml.stderr create mode 100644 tests/misc/projects/issue5002/compile-fast-fail.hxml create mode 100644 tests/misc/projects/issue5002/compile-fast-fail.hxml.stderr create mode 100644 tests/misc/projects/issue5002/compile2-fast-fail.hxml create mode 100644 tests/misc/projects/issue5002/compile2-fast-fail.hxml.stderr create mode 100644 tests/misc/projects/issue5002/compile3-fast-fail.hxml create mode 100644 tests/misc/projects/issue5002/compile3-fast-fail.hxml.stderr create mode 100644 tests/misc/projects/issue5002/compile4-fast-fail.hxml create mode 100644 tests/misc/projects/issue5002/compile4-fast-fail.hxml.stderr diff --git a/src-json/define.json b/src-json/define.json index 15c1d8db2e8..c3a3d03c91b 100644 --- a/src-json/define.json +++ b/src-json/define.json @@ -160,6 +160,11 @@ "doc": "Record per-method execution times in macro/interp mode. Implies eval-stack.", "platforms": ["eval"] }, + { + "name": "FailFast", + "define": "fail-fast", + "doc": "Abort compilation when first error occurs." + }, { "name": "FilterTimes", "define": "filter-times", diff --git a/src/compiler/compilationContext.ml b/src/compiler/compilationContext.ml index 5f1f91489dd..73902263304 100644 --- a/src/compiler/compilationContext.ml +++ b/src/compiler/compilationContext.ml @@ -80,16 +80,24 @@ let message ctx msg = ctx.messages <- msg :: ctx.messages let error ctx ?(depth=0) ?(from_macro = false) msg p = - message ctx (make_compiler_message ~from_macro msg p depth DKCompilerMessage Error); - ctx.has_error <- true + message ctx (make_compiler_message ~from_macro msg p depth DKCompilerMessage Error) + +let after_error ctx = + ctx.has_error <- true; + if Common.fail_fast ctx.com then raise Abort let error_ext ctx (err : Error.error) = Error.recurse_error (fun depth err -> error ~depth ~from_macro:err.err_from_macro ctx (Error.error_msg err.err_message) err.err_pos - ) err + ) err; + after_error ctx + +let error ctx ?(depth=0) ?(from_macro = false) msg p = + error ctx ~depth ~from_macro msg p; + after_error ctx let create_native_lib file extern kind = { lib_file = file; lib_extern = extern; lib_kind = kind; -} \ No newline at end of file +} diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index 34f68860c14..2b8468634b5 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -417,8 +417,6 @@ let compile_safe ctx f = try f () with - | Abort -> - () | Error.Fatal_error err -> error_ext ctx err | Lexer.Error (m,p) -> @@ -454,6 +452,9 @@ with | e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" with _ -> true) && not Helper.is_debug_run -> error ctx (Printexc.to_string e) null_pos +let compile_safe ctx f = + try compile_safe ctx f with Abort -> () + let finalize ctx = ctx.comm.flush ctx; List.iter (fun lib -> lib#close) ctx.com.hxb_libs; diff --git a/src/compiler/messageReporting.ml b/src/compiler/messageReporting.ml index d12d8d01232..f7f76d31123 100644 --- a/src/compiler/messageReporting.ml +++ b/src/compiler/messageReporting.ml @@ -356,10 +356,15 @@ let display_messages ctx on_message = begin let ectx = create_error_context absolute_positions in ectx.max_lines <- get_max_line ectx.max_lines ctx.messages; + let error msg = + ctx.has_error <- true; + on_message MessageSeverity.Error msg + in + let get_formatter _ def default = try get_formatter ctx.com def default with | ConfigError s -> - error ctx s null_pos; + error s; compiler_message_string in @@ -393,7 +398,7 @@ let display_messages ctx on_message = begin end with | Failure e | Sys_error e -> begin let def = Define.get_define_key Define.MessageLogFile in - error ctx (Printf.sprintf "Error opening log file: %s. Logging to file disabled (-D %s)" e def) null_pos; + error (Printf.sprintf "Error opening log file: %s. Logging to file disabled (-D %s)" e def); log_messages := false; end end; diff --git a/src/context/common.ml b/src/context/common.ml index c662ca54a48..55f3bf31cb5 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -469,6 +469,7 @@ let convert_define k = String.concat "_" (ExtString.String.nsplit k "-") let is_next com = defined com HaxeNext +let fail_fast com = defined com FailFast let external_defined ctx k = Define.raw_defined ctx.defines (convert_define k) diff --git a/src/core/define.ml b/src/core/define.ml index d71055df6d4..0071440c373 100644 --- a/src/core/define.ml +++ b/src/core/define.ml @@ -152,7 +152,7 @@ let get_signature def = Parser.parse_macro_ident as well (issue #5682). Note that we should removed flags like use_rtti_doc here. *) - | "display" | "use_rtti_doc" | "macro_times" | "display_details" | "no_copt" | "display_stdin" | "hxb.stats" + | "display" | "use_rtti_doc" | "macro_times" | "display_details" | "no_copt" | "display_stdin" | "hxb.stats" | "fail_fast" | "message.reporting" | "message.log_file" | "message.log_format" | "message.no_color" | "dump" | "dump_dependencies" | "dump_ignore_var_ids" -> acc | _ -> (k ^ "=" ^ v) :: acc diff --git a/tests/misc/projects/Issue6065/compile-fast-fail.hxml b/tests/misc/projects/Issue6065/compile-fast-fail.hxml new file mode 100644 index 00000000000..1c05658d214 --- /dev/null +++ b/tests/misc/projects/Issue6065/compile-fast-fail.hxml @@ -0,0 +1,2 @@ +compile-fail.hxml +-D fail-fast diff --git a/tests/misc/projects/Issue6065/compile-fast-fail.hxml.stderr b/tests/misc/projects/Issue6065/compile-fast-fail.hxml.stderr new file mode 100644 index 00000000000..56668f3d86a --- /dev/null +++ b/tests/misc/projects/Issue6065/compile-fast-fail.hxml.stderr @@ -0,0 +1,8 @@ +Main.hx:8: characters 9-18 : Could not find a suitable overload, reasons follow +Main.hx:8: characters 9-18 : Overload resolution failed for () -> Void +Main.hx:8: characters 13-17 : Too many arguments +Main.hx:8: characters 9-18 : Overload resolution failed for (t : f.T) -> Void +Main.hx:8: characters 13-17 : Constraint check failure for f.T +Main.hx:8: characters 13-17 : ... String should be Int +Main.hx:8: characters 13-17 : ... For function argument 't' +Main.hx:8: characters 9-18 : End of overload failure reasons diff --git a/tests/misc/projects/Issue6065/indent-fast-fail.hxml b/tests/misc/projects/Issue6065/indent-fast-fail.hxml new file mode 100644 index 00000000000..5a550576c0c --- /dev/null +++ b/tests/misc/projects/Issue6065/indent-fast-fail.hxml @@ -0,0 +1,2 @@ +indent-fail.hxml +-D fail-fast diff --git a/tests/misc/projects/Issue6065/indent-fast-fail.hxml.stderr b/tests/misc/projects/Issue6065/indent-fast-fail.hxml.stderr new file mode 100644 index 00000000000..5de57aae190 --- /dev/null +++ b/tests/misc/projects/Issue6065/indent-fast-fail.hxml.stderr @@ -0,0 +1,7 @@ +Main.hx:8: characters 9-18 : Could not find a suitable overload, reasons follow + Main.hx:8: characters 9-18 : Overload resolution failed for () -> Void + Main.hx:8: characters 13-17 : Too many arguments + Main.hx:8: characters 9-18 : Overload resolution failed for (t : f.T) -> Void + Main.hx:8: characters 13-17 : Constraint check failure for f.T + Main.hx:8: characters 13-17 : String should be Int + Main.hx:8: characters 13-17 : For function argument 't' diff --git a/tests/misc/projects/Issue6065/pretty-fast-fail.hxml b/tests/misc/projects/Issue6065/pretty-fast-fail.hxml new file mode 100644 index 00000000000..4983242e142 --- /dev/null +++ b/tests/misc/projects/Issue6065/pretty-fast-fail.hxml @@ -0,0 +1,2 @@ +pretty-fail.hxml +-D fail-fast diff --git a/tests/misc/projects/Issue6065/pretty-fast-fail.hxml.stderr b/tests/misc/projects/Issue6065/pretty-fast-fail.hxml.stderr new file mode 100644 index 00000000000..6ae7cbf1bf0 --- /dev/null +++ b/tests/misc/projects/Issue6065/pretty-fast-fail.hxml.stderr @@ -0,0 +1,20 @@ +[ERROR] Main.hx:8: characters 9-18 + + 8 | C.f("hi"); + | ^^^^^^^^^ + | Could not find a suitable overload, reasons follow + + | Overload resolution failed for () -> Void + + 8 | C.f("hi"); + | ^^^^ + | Too many arguments + + | Overload resolution failed for (t : f.T) -> Void + + 8 | C.f("hi"); + | ^^^^ + | Constraint check failure for f.T + | String should be Int + | For function argument 't' + diff --git a/tests/misc/projects/Issue8019/compile-fast-fail.hxml b/tests/misc/projects/Issue8019/compile-fast-fail.hxml new file mode 100644 index 00000000000..1c05658d214 --- /dev/null +++ b/tests/misc/projects/Issue8019/compile-fast-fail.hxml @@ -0,0 +1,2 @@ +compile-fail.hxml +-D fail-fast diff --git a/tests/misc/projects/Issue8019/compile-fast-fail.hxml.stderr b/tests/misc/projects/Issue8019/compile-fast-fail.hxml.stderr new file mode 100644 index 00000000000..b34a3575506 --- /dev/null +++ b/tests/misc/projects/Issue8019/compile-fast-fail.hxml.stderr @@ -0,0 +1,2 @@ +Macro.hx:9: characters 18-19 : "" is not a valid package name: +Macro.hx:9: characters 18-19 : Package name must not be empty diff --git a/tests/misc/projects/Issue8019/compile3-fast-fail.hxml b/tests/misc/projects/Issue8019/compile3-fast-fail.hxml new file mode 100644 index 00000000000..02597fcd931 --- /dev/null +++ b/tests/misc/projects/Issue8019/compile3-fast-fail.hxml @@ -0,0 +1,2 @@ +compile3-fail.hxml +-D fail-fast diff --git a/tests/misc/projects/Issue8019/compile3-fast-fail.hxml.stderr b/tests/misc/projects/Issue8019/compile3-fast-fail.hxml.stderr new file mode 100644 index 00000000000..32a1a80dc17 --- /dev/null +++ b/tests/misc/projects/Issue8019/compile3-fast-fail.hxml.stderr @@ -0,0 +1 @@ +Macro2.hx:8: characters 18-19 : Module "" does not have a valid name. Module name must not be empty. diff --git a/tests/misc/projects/issue5002/compile-fast-fail.hxml b/tests/misc/projects/issue5002/compile-fast-fail.hxml new file mode 100644 index 00000000000..1c05658d214 --- /dev/null +++ b/tests/misc/projects/issue5002/compile-fast-fail.hxml @@ -0,0 +1,2 @@ +compile-fail.hxml +-D fail-fast diff --git a/tests/misc/projects/issue5002/compile-fast-fail.hxml.stderr b/tests/misc/projects/issue5002/compile-fast-fail.hxml.stderr new file mode 100644 index 00000000000..056b0cf3c3f --- /dev/null +++ b/tests/misc/projects/issue5002/compile-fast-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:1: characters 1-8 : "0" is not a valid field name. diff --git a/tests/misc/projects/issue5002/compile2-fast-fail.hxml b/tests/misc/projects/issue5002/compile2-fast-fail.hxml new file mode 100644 index 00000000000..4585f4855bf --- /dev/null +++ b/tests/misc/projects/issue5002/compile2-fast-fail.hxml @@ -0,0 +1,2 @@ +compile2-fail.hxml +-D fail-fast diff --git a/tests/misc/projects/issue5002/compile2-fast-fail.hxml.stderr b/tests/misc/projects/issue5002/compile2-fast-fail.hxml.stderr new file mode 100644 index 00000000000..2f6dbe6ff04 --- /dev/null +++ b/tests/misc/projects/issue5002/compile2-fast-fail.hxml.stderr @@ -0,0 +1 @@ +Main2.hx:6: characters 3-32 : "0_variable" is not a valid variable name. diff --git a/tests/misc/projects/issue5002/compile3-fast-fail.hxml b/tests/misc/projects/issue5002/compile3-fast-fail.hxml new file mode 100644 index 00000000000..02597fcd931 --- /dev/null +++ b/tests/misc/projects/issue5002/compile3-fast-fail.hxml @@ -0,0 +1,2 @@ +compile3-fail.hxml +-D fail-fast diff --git a/tests/misc/projects/issue5002/compile3-fast-fail.hxml.stderr b/tests/misc/projects/issue5002/compile3-fast-fail.hxml.stderr new file mode 100644 index 00000000000..2b10bd17bad --- /dev/null +++ b/tests/misc/projects/issue5002/compile3-fast-fail.hxml.stderr @@ -0,0 +1 @@ +Main3.hx:10: characters 18-19 : Module "lowercase" does not have a valid name. Module name should start with an uppercase letter: "lowercase" diff --git a/tests/misc/projects/issue5002/compile4-fast-fail.hxml b/tests/misc/projects/issue5002/compile4-fast-fail.hxml new file mode 100644 index 00000000000..e4736d81054 --- /dev/null +++ b/tests/misc/projects/issue5002/compile4-fast-fail.hxml @@ -0,0 +1,2 @@ +compile4-fail.hxml +-D fail-fast diff --git a/tests/misc/projects/issue5002/compile4-fast-fail.hxml.stderr b/tests/misc/projects/issue5002/compile4-fast-fail.hxml.stderr new file mode 100644 index 00000000000..7f4fc7338c2 --- /dev/null +++ b/tests/misc/projects/issue5002/compile4-fast-fail.hxml.stderr @@ -0,0 +1 @@ +Main4.hx:3: characters 7-9 : Variable names starting with a dollar are not allowed: "$i" From ea964ad99ea99f6f2f787ca1a8e23b102df6a464 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 27 Mar 2024 08:12:46 +0100 Subject: [PATCH 27/49] [hxb] detect need for local context in nested anons (#11617) * [hxb] detect need for local context in nested anons * [hxb] add compiler failure message * [tests] add tests for 11589 * [tests] add original Hide issue too * [hxb] handle another edge case --- src/compiler/hxb/hxbReader.ml | 17 ++++++++++- src/compiler/hxb/hxbWriter.ml | 29 ++++++++++--------- tests/server/src/cases/issues/Issue11589.hx | 27 +++++++++++++++++ .../test/templates/issues/Issue11589/Main.hx | 3 ++ .../test/templates/issues/Issue11589/Main1.hx | 8 +++++ .../test/templates/issues/Issue11589/Main2.hx | 6 ++++ 6 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 tests/server/src/cases/issues/Issue11589.hx create mode 100644 tests/server/test/templates/issues/Issue11589/Main.hx create mode 100644 tests/server/test/templates/issues/Issue11589/Main1.hx create mode 100644 tests/server/test/templates/issues/Issue11589/Main2.hx diff --git a/src/compiler/hxb/hxbReader.ml b/src/compiler/hxb/hxbReader.ml index 0f5e8074d61..aa20a40a449 100644 --- a/src/compiler/hxb/hxbReader.ml +++ b/src/compiler/hxb/hxbReader.ml @@ -1973,11 +1973,26 @@ class hxb_reader | EOM -> incr stats.modules_fully_restored; + method private die chunk msg = + let msg = + (Printf.sprintf "Compiler failure while reading hxb chunk %s of %s: %s\n" (string_of_chunk_kind chunk) (s_type_path mpath) (msg)) + ^ "Please submit an issue at https://github.com/HaxeFoundation/haxe/issues/new\n" + ^ "Attach the following information:" + in + let backtrace = Printexc.raw_backtrace_to_string (Printexc.get_raw_backtrace ()) in + let s = Printf.sprintf "%s\nHaxe: %s\n%s" msg s_version_full backtrace in + failwith s + method private read_chunk_data kind = let path = String.concat "_" (ExtLib.String.nsplit (s_type_path mpath) ".") in let id = ["hxb";"read";string_of_chunk_kind kind;path] in let close = Timer.timer id in - self#read_chunk_data' kind; + try + self#read_chunk_data' kind + with Invalid_argument msg -> begin + close(); + self#die kind msg + end; close() method read_chunks (new_api : hxb_reader_api) (chunks : cached_chunks) = diff --git a/src/compiler/hxb/hxbWriter.ml b/src/compiler/hxb/hxbWriter.ml index 23ea698e153..d426221c52b 100644 --- a/src/compiler/hxb/hxbWriter.ml +++ b/src/compiler/hxb/hxbWriter.ml @@ -469,6 +469,7 @@ type hxb_writer = { mutable local_type_parameters : (typed_type_param,unit) IdentityPool.t; mutable field_stack : unit list; mutable wrote_local_type_param : bool; + mutable needs_local_context : bool; unbound_ttp : (typed_type_param,unit) IdentityPool.t; t_instance_chunk : Chunk.t; } @@ -1006,12 +1007,11 @@ module HxbWriter = struct write_pos writer v.v_pos let rec write_anon writer (an : tanon) = - let needs_local_context = ref false in let write_fields () = let restore = start_temporary_chunk writer 256 in let i = ref 0 in PMap.iter (fun _ cf -> - write_anon_field_ref writer needs_local_context cf; + write_anon_field_ref writer cf; incr i; ) an.a_fields; let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in @@ -1035,8 +1035,7 @@ module HxbWriter = struct assert false | AbstractStatics _ -> assert false - end; - !needs_local_context + end and write_anon_ref writer (an : tanon) = let pfm = Option.get (writer.anon_id#identify_anon ~strict:true an) in @@ -1046,9 +1045,10 @@ module HxbWriter = struct Chunk.write_uleb128 writer.chunk index with Not_found -> let restore = start_temporary_chunk writer 256 in - let needs_local_context = write_anon writer an in + writer.needs_local_context <- false; + write_anon writer an; let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in - if needs_local_context then begin + if writer.needs_local_context then begin let index = Pool.add writer.anons pfm.pfm_path None in Chunk.write_u8 writer.chunk 1; Chunk.write_uleb128 writer.chunk index; @@ -1059,7 +1059,7 @@ module HxbWriter = struct Chunk.write_uleb128 writer.chunk index; end - and write_anon_field_ref writer needs_local_context cf = + and write_anon_field_ref writer cf = try let index = HashedIdentityPool.get writer.anon_fields cf.cf_name cf in Chunk.write_u8 writer.chunk 0; @@ -1067,15 +1067,14 @@ module HxbWriter = struct with Not_found -> let restore = start_temporary_chunk writer 256 in let old = writer.wrote_local_type_param in + writer.wrote_local_type_param <- false; ignore(write_class_field_and_overloads_data writer true cf); - let wrote_local_type_param = writer.wrote_local_type_param in - writer.wrote_local_type_param <- old; let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in - if wrote_local_type_param then begin + if writer.needs_local_context || writer.wrote_local_type_param then begin (* If we access something from the method scope, we have to write the anon field immediately. This should be fine because in such cases the field cannot be referenced elsewhere. *) let index = HashedIdentityPool.add writer.anon_fields cf.cf_name cf None in - needs_local_context := true; + writer.needs_local_context <- true; Chunk.write_u8 writer.chunk 1; Chunk.write_uleb128 writer.chunk index; Chunk.write_bytes writer.chunk bytes @@ -1083,7 +1082,8 @@ module HxbWriter = struct let index = HashedIdentityPool.add writer.anon_fields cf.cf_name cf (Some bytes) in Chunk.write_u8 writer.chunk 0; Chunk.write_uleb128 writer.chunk index; - end + end; + writer.wrote_local_type_param <- old (* Type instances *) @@ -1565,7 +1565,7 @@ module HxbWriter = struct | TField(e1,FAnon cf) -> Chunk.write_u8 writer.chunk 104; loop e1; - write_anon_field_ref writer (ref false) cf; + write_anon_field_ref writer cf; true; | TField(e1,FClosure(Some(c,tl),cf)) -> Chunk.write_u8 writer.chunk 105; @@ -1577,7 +1577,7 @@ module HxbWriter = struct | TField(e1,FClosure(None,cf)) -> Chunk.write_u8 writer.chunk 106; loop e1; - write_anon_field_ref writer (ref false) cf; + write_anon_field_ref writer cf; true; | TField(e1,FEnum(en,ef)) -> Chunk.write_u8 writer.chunk 107; @@ -2312,6 +2312,7 @@ let create config warn anon_id = local_type_parameters = IdentityPool.create (); field_stack = []; wrote_local_type_param = false; + needs_local_context = false; unbound_ttp = IdentityPool.create (); t_instance_chunk = Chunk.create EOM cp 32; } diff --git a/tests/server/src/cases/issues/Issue11589.hx b/tests/server/src/cases/issues/Issue11589.hx new file mode 100644 index 00000000000..2f75aaa89ca --- /dev/null +++ b/tests/server/src/cases/issues/Issue11589.hx @@ -0,0 +1,27 @@ +package cases.issues; + +class Issue11589 extends TestCase { + function test(_) { + vfs.putContent("Main.hx", getTemplate("issues/Issue11589/Main.hx")); + var args = ["--main", "Main.hx", "--no-output"]; + runHaxe(args); + runHaxe(args); + Assert.isFalse(lastResult.hasError); + } + + function testNestedField(_) { + vfs.putContent("Main.hx", getTemplate("issues/Issue11589/Main1.hx")); + var args = ["--main", "Main.hx", "--no-output"]; + runHaxe(args); + runHaxe(args); + Assert.isFalse(lastResult.hasError); + } + + function testNestedFieldUsed(_) { + vfs.putContent("Main.hx", getTemplate("issues/Issue11589/Main2.hx")); + var args = ["--main", "Main.hx", "--no-output"]; + runHaxe(args); + runHaxe(args); + Assert.isFalse(lastResult.hasError); + } +} diff --git a/tests/server/test/templates/issues/Issue11589/Main.hx b/tests/server/test/templates/issues/Issue11589/Main.hx new file mode 100644 index 00000000000..8ca9cd6ae2f --- /dev/null +++ b/tests/server/test/templates/issues/Issue11589/Main.hx @@ -0,0 +1,3 @@ +function main() {} + +typedef Foo = {} & { foo:T } diff --git a/tests/server/test/templates/issues/Issue11589/Main1.hx b/tests/server/test/templates/issues/Issue11589/Main1.hx new file mode 100644 index 00000000000..b219dc81c53 --- /dev/null +++ b/tests/server/test/templates/issues/Issue11589/Main1.hx @@ -0,0 +1,8 @@ +function main() {} + +typedef Foo = { foo : { bar : T } } + +typedef Bar = { + function foo( elements : Array<{ value : T }> ) : Void; + function bar( foo : T, bar : { baz : Bool } ) : Void; +} diff --git a/tests/server/test/templates/issues/Issue11589/Main2.hx b/tests/server/test/templates/issues/Issue11589/Main2.hx new file mode 100644 index 00000000000..ab3ad3a2a41 --- /dev/null +++ b/tests/server/test/templates/issues/Issue11589/Main2.hx @@ -0,0 +1,6 @@ +function main() { + foo(""); +} + +function foo(v:T):Foo return {foo:{bar:v}} +typedef Foo = { foo : { bar : T } } From 0671176723f2084e56ca8addcb026776053e00cb Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 28 Mar 2024 09:01:19 +0100 Subject: [PATCH 28/49] Avoid printing 'CompilationContext.Abort' after error --- src/compiler/compiler.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index 2b8468634b5..c263048c025 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -446,7 +446,7 @@ with error ctx ("Error: No completion point was found") null_pos | DisplayException.DisplayException dex -> DisplayOutput.handle_display_exception ctx dex - | Out_of_memory | EvalTypes.Sys_exit _ | Hlinterp.Sys_exit _ | DisplayProcessingGlobals.Completion _ as exc -> + | Abort | Out_of_memory | EvalTypes.Sys_exit _ | Hlinterp.Sys_exit _ | DisplayProcessingGlobals.Completion _ as exc -> (* We don't want these to be caught by the catchall below *) raise exc | e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" with _ -> true) && not Helper.is_debug_run -> From 433fbdf33bfb6dd3897bf03cbed1099cfca4e0b8 Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Thu, 28 Mar 2024 09:03:51 +0100 Subject: [PATCH 29/49] [hl] add std.hl.Gc.getLiveObjects for next hl version (#11599) --- std/hl/Gc.hx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/std/hl/Gc.hx b/std/hl/Gc.hx index 03df18e2f08..9fa76c0b154 100644 --- a/std/hl/Gc.hx +++ b/std/hl/Gc.hx @@ -69,6 +69,22 @@ class Gc { return v; } + #if (hl_ver >= version("1.15.0")) + /** + Count live objects of class `cl`, and get at most `maxCount` elements in an array. + **/ + public static function getLiveObjects(cl:Class, maxCount:Int = 0) { + var arr = new hl.NativeArray(maxCount); + var count = _getLiveObjects(cast(cl,hl.BaseType).__type__, arr); + var objs = new Array(); + for (i in 0...maxCount) { + if (arr[i] == null) break; + objs.push(arr[i]); + } + return {count: count, objs: objs}; + } + #end + /** Enter/leave a blocking section: when in a blocking section the thread cannot allocate any memory but other threads will not wait for it for collecting memory. @@ -89,4 +105,10 @@ class Gc { } @:hlNative("std", "gc_set_flags") static function _set_flags(v:Int) {} + + #if (hl_ver >= version("1.15.0")) + @:hlNative("std", "gc_get_live_objects") static function _getLiveObjects(type:hl.Type, arr:hl.NativeArray):Int { + return 0; + } + #end } From cbb8d6e3f861f1ad2b265e3f7e9f659b32a18346 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 28 Mar 2024 14:36:19 +0100 Subject: [PATCH 30/49] Fix @:generic with multiple calls (#11619) * See where CI complains * [tests] add test for 11608 * Skip clones too --- src/typing/generic.ml | 13 ++----------- tests/misc/projects/Issue11608/Test.hx | 17 +++++++++++++++++ tests/misc/projects/Issue11608/compile.hxml | 1 + 3 files changed, 20 insertions(+), 11 deletions(-) create mode 100644 tests/misc/projects/Issue11608/Test.hx create mode 100644 tests/misc/projects/Issue11608/compile.hxml diff --git a/src/typing/generic.ml b/src/typing/generic.ml index 22ef367f376..6f12c785a94 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -452,18 +452,9 @@ let type_generic_function ctx fa fcc with_type p = ) monos; let el = fcc.fc_args in let gctx = make_generic ctx cf.cf_params monos (Meta.has (Meta.Custom ":debug.generic") cf.cf_meta) p in + let fc_type = build_instances ctx fcc.fc_type p in let name = cf.cf_name ^ "_" ^ gctx.name in let params = extract_type_parameters monos in - let clones = List.map (fun ttp -> - let name_path = if (fst ttp.ttp_class.cl_path) = [cf.cf_name] then ([name],ttp.ttp_name) else ttp.ttp_class.cl_path in - clone_type_parameter gctx c.cl_module name_path ttp - ) params in - let param_subst = List.map2 (fun ttp ttp' -> - (ttp.ttp_type,ttp') - ) params clones in - let param_subst = List.map (fun (t,ttp) -> t,(ttp.ttp_type,None)) param_subst in - let gctx = {gctx with subst = param_subst @ gctx.subst} in - let fc_type = build_instances ctx (generic_substitute_type gctx fcc.fc_type) p in let unify_existing_field tcf pcf = try unify_raise tcf fc_type p with Error ({ err_message = Unify _; err_depth = depth } as err) -> @@ -519,7 +510,7 @@ let type_generic_function ctx fa fcc with_type p = | _ -> true ) cf.cf_meta in cf2.cf_meta <- (Meta.NoCompletion,[],p) :: (Meta.NoUsing,[],p) :: (Meta.GenericInstance,[],p) :: meta; - cf2.cf_params <- clones + cf2.cf_params <- params in let mk_cf2 name = mk_field ~static:stat name fc_type cf.cf_pos cf.cf_name_pos diff --git a/tests/misc/projects/Issue11608/Test.hx b/tests/misc/projects/Issue11608/Test.hx new file mode 100644 index 00000000000..b5b34cb3a92 --- /dev/null +++ b/tests/misc/projects/Issue11608/Test.hx @@ -0,0 +1,17 @@ +using Test; + +class Test { + static public function main() {} + + static function doF2(f: T -> Float) : T { + var arr = []; + arr.doF(f); + arr.doF(f); + return arr.doF(f); + } + + @:generic + static function doF(array: Array, f: T -> Float) : T { + return null; + } +} diff --git a/tests/misc/projects/Issue11608/compile.hxml b/tests/misc/projects/Issue11608/compile.hxml new file mode 100644 index 00000000000..dc911ff3799 --- /dev/null +++ b/tests/misc/projects/Issue11608/compile.hxml @@ -0,0 +1 @@ +-main Test From ed66cbe398e6d9d5913c67a56f73dee360652771 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Sat, 30 Mar 2024 07:38:47 +0100 Subject: [PATCH 31/49] Catch missing standard library in init macros (#11621) --- src/core/error.ml | 7 +++++++ src/typing/macroContext.ml | 5 ++++- src/typing/typerEntry.ml | 6 +----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/core/error.ml b/src/core/error.ml index c1b2232693c..3a2625f10f4 100644 --- a/src/core/error.ml +++ b/src/core/error.ml @@ -328,6 +328,13 @@ let raise_msg ?(depth = 0) msg p = raise_error_msg ~depth (Custom msg) p let raise_typing_error ?(depth = 0) msg p = raise_msg ~depth msg p let raise_typing_error_ext err = raise_error err +let raise_std_not_found () = + try + let std_path = Sys.getenv "HAXE_STD_PATH" in + raise_typing_error ("Standard library not found. Please check your `HAXE_STD_PATH` environment variable (current value: \"" ^ std_path ^ "\")") null_pos + with Not_found -> + raise_typing_error "Standard library not found. You may need to set your `HAXE_STD_PATH` environment variable" null_pos + let error_require r p = if r = "" then raise_typing_error "This field is not available with the current compilation flags" p diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index dce64f76af1..b95e664c4e2 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -697,7 +697,10 @@ let create_macro_context com = [cp#clone] ) com.class_paths#as_list; (* Eval _std must be in front so we don't look into hxnodejs or something. *) - com2.class_paths#add (Option.get !eval_std); + (* This can run before `TyperEntry.create`, so in order to display nice error when std is not found, this needs to be checked here too *) + (match !eval_std with + | Some std -> com2.class_paths#add std + | None -> Error.raise_std_not_found ()); let defines = adapt_defines_to_macro_context com2.defines; in com2.defines.values <- defines.values; com2.defines.defines_signature <- None; diff --git a/src/typing/typerEntry.ml b/src/typing/typerEntry.ml index 04111d43d27..4da3d4c6f42 100644 --- a/src/typing/typerEntry.ml +++ b/src/typing/typerEntry.ml @@ -63,11 +63,7 @@ let create com macros = TypeloadModule.load_module ctx ([],"StdTypes") null_pos with Error { err_message = Module_not_found ([],"StdTypes") } -> - try - let std_path = Sys.getenv "HAXE_STD_PATH" in - raise_typing_error ("Standard library not found. Please check your `HAXE_STD_PATH` environment variable (current value: \"" ^ std_path ^ "\")") null_pos - with Not_found -> - raise_typing_error "Standard library not found. You may need to set your `HAXE_STD_PATH` environment variable" null_pos + Error.raise_std_not_found () ); (* We always want core types to be available so we add them as default imports (issue #1904 and #3131). *) List.iter (fun mt -> From aefa949324263e54414dfc14ea51e6db717ac209 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Sat, 30 Mar 2024 07:49:24 +0100 Subject: [PATCH 32/49] remove trailing slash from HAXE_STD_PATH --- src/compiler/compiler.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index c263048c025..f780a042459 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -190,6 +190,7 @@ module Setup = struct let get_std_class_paths () = try let p = Sys.getenv "HAXE_STD_PATH" in + let p = Path.remove_trailing_slash p in let rec loop = function | drive :: path :: l -> if String.length drive = 1 && ((drive.[0] >= 'a' && drive.[0] <= 'z') || (drive.[0] >= 'A' && drive.[0] <= 'Z')) then From d283959f8f3e7ce4972eb094df20c8cc7b9f73b3 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 3 Apr 2024 09:31:12 +0200 Subject: [PATCH 33/49] [hxb] Display compiler failure when failing write_full_path --- src/compiler/hxb/hxbReader.ml | 9 ++++++--- src/compiler/hxb/hxbWriter.ml | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/compiler/hxb/hxbReader.ml b/src/compiler/hxb/hxbReader.ml index aa20a40a449..f85b67218d8 100644 --- a/src/compiler/hxb/hxbReader.ml +++ b/src/compiler/hxb/hxbReader.ml @@ -1973,13 +1973,16 @@ class hxb_reader | EOM -> incr stats.modules_fully_restored; - method private die chunk msg = + method private get_backtrace () = Printexc.get_raw_backtrace () + method private get_callstack () = Printexc.get_callstack 200 + + method private failwith chunk msg backtrace = let msg = (Printf.sprintf "Compiler failure while reading hxb chunk %s of %s: %s\n" (string_of_chunk_kind chunk) (s_type_path mpath) (msg)) ^ "Please submit an issue at https://github.com/HaxeFoundation/haxe/issues/new\n" ^ "Attach the following information:" in - let backtrace = Printexc.raw_backtrace_to_string (Printexc.get_raw_backtrace ()) in + let backtrace = Printexc.raw_backtrace_to_string backtrace in let s = Printf.sprintf "%s\nHaxe: %s\n%s" msg s_version_full backtrace in failwith s @@ -1991,7 +1994,7 @@ class hxb_reader self#read_chunk_data' kind with Invalid_argument msg -> begin close(); - self#die kind msg + self#failwith kind msg (self#get_backtrace ()) end; close() diff --git a/src/compiler/hxb/hxbWriter.ml b/src/compiler/hxb/hxbWriter.ml index d426221c52b..d0358465963 100644 --- a/src/compiler/hxb/hxbWriter.ml +++ b/src/compiler/hxb/hxbWriter.ml @@ -475,6 +475,19 @@ type hxb_writer = { } module HxbWriter = struct + let get_backtrace () = Printexc.get_raw_backtrace () + let get_callstack () = Printexc.get_callstack 200 + + let failwith writer msg backtrace = + let msg = + (Printf.sprintf "Compiler failure while writing hxb chunk %s of %s: %s\n" (string_of_chunk_kind writer.chunk.kind) (s_type_path writer.current_module.m_path) (msg)) + ^ "Please submit an issue at https://github.com/HaxeFoundation/haxe/issues/new\n" + ^ "Attach the following information:" + in + let backtrace = Printexc.raw_backtrace_to_string backtrace in + let s = Printf.sprintf "%s\nHaxe: %s\n%s" msg s_version_full backtrace in + failwith s + let in_nested_scope writer = match writer.field_stack with | [] -> false (* can happen for cl_init and in EXD *) | [_] -> false @@ -528,7 +541,7 @@ module HxbWriter = struct let write_full_path writer (pack : string list) (mname : string) (tname : string) = Chunk.write_list writer.chunk pack (Chunk.write_string writer.chunk); if mname = "" || tname = "" then - die (Printf.sprintf "write_full_path: pack = %s, mname = %s, tname = %s" (String.concat "." pack) mname tname) __LOC__; + failwith writer (Printf.sprintf "write_full_path: pack = %s, mname = %s, tname = %s" (String.concat "." pack) mname tname) (get_callstack ()); Chunk.write_string writer.chunk mname; Chunk.write_string writer.chunk tname From 0bdc03a89df9a5e7abc401c6fac16630815b47ad Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 3 Apr 2024 09:45:14 +0200 Subject: [PATCH 34/49] [macro] Remove CompilationServer.setModuleCheckPolicy options (#11615) * [macro] Remove CompilationServer.addModuleCheckPolicy * [std] remove more special #if display cases * [macro] Add back some module check policies through CompilationServer.setModuleFileSystemCheckPolicy * Naming * Revert renaming * Rename fix --- src/compiler/compilationCache.ml | 5 --- src/compiler/server.ml | 8 ++--- src/core/tType.ml | 5 ++- src/macro/macroApi.ml | 6 ++-- src/typing/macroContext.ml | 15 +++----- std/haxe/macro/CompilationServer.hx | 51 +++++----------------------- std/haxe/macro/ExampleJSGenerator.hx | 2 +- std/haxe/macro/Format.hx | 2 +- 8 files changed, 25 insertions(+), 69 deletions(-) diff --git a/src/compiler/compilationCache.ml b/src/compiler/compilationCache.ml index 984ce459e24..abc7d62a99e 100644 --- a/src/compiler/compilationCache.ml +++ b/src/compiler/compilationCache.ml @@ -310,8 +310,3 @@ class cache = object(self) end type t = cache - -type context_options = - | NormalContext - | MacroContext - | NormalAndMacroContext diff --git a/src/compiler/server.ml b/src/compiler/server.ml index 6ba694322b2..dbe3253c4d6 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -291,7 +291,7 @@ let check_module sctx com m_path m_extra p = end in let has_policy policy = List.mem policy m_extra.m_check_policy || match policy with - | NoCheckShadowing | NoCheckFileTimeModification when !ServerConfig.do_not_check_modules && !Parser.display_mode <> DMNone -> true + | NoFileSystemCheck when !ServerConfig.do_not_check_modules && !Parser.display_mode <> DMNone -> true | _ -> false in let check_file () = @@ -325,9 +325,9 @@ let check_module sctx com m_path m_extra p = in let check () = try - if not (has_policy NoCheckShadowing) then check_module_path(); - if not (has_policy NoCheckFileTimeModification) || Path.file_extension (Path.UniqueKey.lazy_path m_extra.m_file) <> "hx" then check_file(); - if not (has_policy NoCheckDependencies) then check_dependencies(); + check_module_path(); + if not (has_policy NoFileSystemCheck) || Path.file_extension (Path.UniqueKey.lazy_path m_extra.m_file) <> "hx" then check_file(); + check_dependencies(); None with | Dirty reason -> diff --git a/src/core/tType.ml b/src/core/tType.ml index 39f5d48d8a6..7d6259285a2 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -26,10 +26,9 @@ and method_kind = | MethMacro type module_check_policy = - | NoCheckFileTimeModification + | NoFileSystemCheck + | CheckFileModificationTime | CheckFileContentModification - | NoCheckDependencies - | NoCheckShadowing type module_tainting_reason = | CheckDisplayFile diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index cfaeb7086f5..22686caa6bf 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -56,7 +56,7 @@ type 'value compiler_api = { add_global_metadata : string -> string -> (bool * bool * bool) -> pos -> unit; register_define : string -> Define.user_define -> unit; register_metadata : string -> Meta.user_meta -> unit; - add_module_check_policy : string list -> int list -> bool -> int -> unit; + add_module_check_policy : string list -> int list -> bool -> unit; decode_expr : 'value -> Ast.expr; encode_expr : Ast.expr -> 'value; encode_ctype : Ast.type_hint -> 'value; @@ -2292,10 +2292,10 @@ let macro_api ccom get_api = vnull ); (* Compilation server *) - "server_add_module_check_policy", vfun4 (fun filter policy recursive context_options -> + "server_add_module_check_policy", vfun3 (fun filter policy recursive -> let filter = List.map decode_string (decode_array filter) in let policy = List.map decode_int (decode_array policy) in - (get_api()).add_module_check_policy filter policy (decode_bool recursive) (decode_int context_options); + (get_api()).add_module_check_policy filter policy (decode_bool recursive); vnull ); "server_invalidate_files", vfun1 (fun a -> diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index b95e664c4e2..7f428adb155 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -257,7 +257,7 @@ let make_macro_com_api com mcom p = com.global_metadata <- (ExtString.String.nsplit s1 ".",m,config) :: com.global_metadata; ) meta; ); - add_module_check_policy = (fun sl il b i -> + add_module_check_policy = (fun sl il b -> Interp.exc_string "unsupported" ); register_define = (fun s data -> Define.register_user_define com.user_defines s data); @@ -526,20 +526,15 @@ let make_macro_api ctx mctx p = ctx.com.global_metadata <- (ExtString.String.nsplit s1 ".",m,config) :: ctx.com.global_metadata; ) meta; ); - MacroApi.add_module_check_policy = (fun sl il b i -> + MacroApi.add_module_check_policy = (fun sl il b -> let add ctx = ctx.g.module_check_policies <- (List.fold_left (fun acc s -> (ExtString.String.nsplit s ".",List.map Obj.magic il,b) :: acc) ctx.g.module_check_policies sl); ctx.com.module_lut#iter (fun _ m -> m.m_extra.m_check_policy <- TypeloadModule.get_policy ctx.g m.m_path); in - let add_macro ctx = match ctx.g.macros with + add ctx; + match ctx.g.macros with | None -> () - | Some(_,mctx) -> add mctx; - in - let open CompilationCache in - match Obj.magic i with - | NormalContext -> add ctx - | MacroContext -> add_macro ctx - | NormalAndMacroContext -> add ctx; add_macro ctx; + | Some(_,mctx) -> add mctx ); MacroApi.with_imports = (fun imports usings f -> let restore_resolution = ctx.m.import_resolution#save in diff --git a/std/haxe/macro/CompilationServer.hx b/std/haxe/macro/CompilationServer.hx index dbefb7ecdcf..921611cf386 100644 --- a/std/haxe/macro/CompilationServer.hx +++ b/std/haxe/macro/CompilationServer.hx @@ -28,47 +28,18 @@ enum abstract ModuleCheckPolicy(Int) { /** Disables file modification checks, avoiding some filesystem operations. **/ - var NoCheckFileTimeModification = 0; + var NoFileSystemCheck = 0; /** - If a file is modified, also checks if its content changed. This check - is not free, but useful when .hx files are auto-generated. - **/ - var CheckFileContentModification = 1; - - /** - Disables dependency checks of the module. - - This should only be used for modules that don't depend on any module that - might change. It is effectively a promise to the compiler that the module - is unaffected by changes made to other modules. If that promise is broken, - the compiler is sad and things probably stop working. + Default behavior: check last modification time. **/ - var NoCheckDependencies = 2; - - /** - Disables file shadowing checks. Shadowing can occur when a new file - is added to a class-path that has higher priority than the class-path - of the current module file. - **/ - var NoCheckShadowing = 3; -} + var CheckFileModificationTime = 1; -enum abstract ContextOptions(Int) { /** - Affects only the normal context. - **/ - var NormalContext = 0; - - /** - Affects only the macro context. - **/ - var MacroContext = 1; - - /** - Affects the normal and macro contexts. + If a file is modified, also checks if its content changed. This check + is not free, but useful when .hx files are auto-generated. **/ - var NormalAndMacroContext = 2; + var CheckFileContentModification = 2; } /** @@ -76,7 +47,7 @@ enum abstract ContextOptions(Int) { `--macro server.field(args)`. **/ class CompilationServer { - #if (macro || display) + #if macro /** Sets the `ModuleCheckPolicy` of all files whose dot-path matches an element of `pathFilters`. @@ -89,16 +60,12 @@ class CompilationServer { everything (if `recursive = true`) or only top-level types (if `recursive = false`). - The argument `contextOptions` determines which context (normal, macro - or both) this affects. - If a call to this function is added to the compilation parameters, the compilation server should be restarted to ensure it takes effect. **/ - static public function setModuleCheckPolicy(pathFilters:Array, policy:Array, ?recursive = true, - ?contextOptions:ContextOptions = NormalContext) { + static public function setModuleCheckPolicy(pathFilters:Array, policy:Array, ?recursive = true) { Context.onAfterInitMacros(() -> { - @:privateAccess Compiler.load("server_add_module_check_policy", 4)(pathFilters, policy, recursive, contextOptions); + @:privateAccess Compiler.load("server_add_module_check_policy", 4)(pathFilters, policy, recursive); }); } diff --git a/std/haxe/macro/ExampleJSGenerator.hx b/std/haxe/macro/ExampleJSGenerator.hx index 05d7ec47c07..9cf78bd6035 100644 --- a/std/haxe/macro/ExampleJSGenerator.hx +++ b/std/haxe/macro/ExampleJSGenerator.hx @@ -256,7 +256,7 @@ class ExampleJSGenerator { sys.io.File.saveContent(api.outputFile, buf.toString()); } - #if (macro || display) + #if macro public static function use() { Compiler.setCustomJSGenerator(function(api) new ExampleJSGenerator(api).generate()); } diff --git a/std/haxe/macro/Format.hx b/std/haxe/macro/Format.hx index afcb0690643..b556a9059b5 100644 --- a/std/haxe/macro/Format.hx +++ b/std/haxe/macro/Format.hx @@ -29,7 +29,7 @@ import haxe.macro.Context; The actual macro implemented for Std.format **/ class Format { - #if (macro || display) + #if macro public static function format(estr:Expr) { var str = switch (estr.expr) { case EConst(c): switch (c) { From 2aa1b528f9782e506f0e370f3203f1af7460bc11 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 4 Apr 2024 07:46:18 +0200 Subject: [PATCH 35/49] Apply @:using after build macros (#11625) * Apply @:using after running build macro Allows build macro to provide such metadata * [tests] Add test for @:using added by build macro * Factorize t_infos calls --- src/typing/typeloadFields.ml | 44 +++++++++++---------- tests/misc/projects/Issue11625/Macro.hx | 5 +++ tests/misc/projects/Issue11625/Main.hx | 10 +++++ tests/misc/projects/Issue11625/compile.hxml | 1 + 4 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 tests/misc/projects/Issue11625/Macro.hx create mode 100644 tests/misc/projects/Issue11625/Main.hx create mode 100644 tests/misc/projects/Issue11625/compile.hxml diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index 55860c9ef63..92f67fef2e6 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -377,7 +377,11 @@ let resolve_type_import ctx p i = [i] let build_module_def ctx mt meta fvars fbuild = - let is_typedef = match mt with TTypeDecl _ -> true | _ -> false in + let is_typedef, ti = match mt with + | TClassDecl { cl_kind = KAbstractImpl a } -> false, t_infos (TAbstractDecl a) + | TTypeDecl _ -> true, t_infos mt + | _ -> false, t_infos mt + in let loop f_build = function | Meta.Build,args,p when not is_typedef -> (fun () -> let epath, el = (match args with @@ -394,31 +398,13 @@ let build_module_def ctx mt meta fvars fbuild = in if ctx.com.is_macro_context then raise_typing_error "You cannot use @:build inside a macro : make sure that your type is not used in macro" p; let old = ctx.c.get_build_infos in - ctx.c.get_build_infos <- (fun() -> Some (mt, extract_param_types (t_infos mt).mt_params, fvars())); + ctx.c.get_build_infos <- (fun() -> Some (mt, extract_param_types ti.mt_params, fvars())); let r = try ctx.g.do_macro ctx MBuild cpath meth el p with e -> ctx.c.get_build_infos <- old; raise e in ctx.c.get_build_infos <- old; (match r with | MError | MMacroInMacro -> raise_typing_error "Build failure" p | MSuccess e -> fbuild e) ) :: f_build - | Meta.Using,el,p -> (fun () -> - List.iter (fun e -> - try - let path = List.rev (string_pos_list_of_expr_path_raise e) in - let types,filter_classes = ImportHandling.handle_using ctx path (pos e) in - let ti = - match mt with - | TClassDecl { cl_kind = KAbstractImpl a } -> t_infos (TAbstractDecl a) - | _ -> t_infos mt - in - (* Delay for #10107, but use delay_late to make sure base classes run before their children do. *) - delay_late ctx.g PConnectField (fun () -> - ti.mt_using <- (filter_classes types) @ ti.mt_using - ) - with Exit -> - raise_typing_error "dot path expected" (pos e) - ) el; - ) :: f_build | _ -> f_build in @@ -432,7 +418,6 @@ let build_module_def ctx mt meta fvars fbuild = ) | TClassDecl { cl_super = csup; cl_implements = interfaces; cl_kind = kind } -> (* Go for @:using in parents and interfaces *) - let ti = t_infos mt in let inherit_using (c,_) = ti.mt_using <- ti.mt_using @ (t_infos (TClassDecl c)).mt_using in @@ -445,6 +430,23 @@ let build_module_def ctx mt meta fvars fbuild = None in List.iter (fun f -> f()) (List.rev f_build); + let apply_using = function + | Meta.Using,el,p -> + List.iter (fun e -> + try + let path = List.rev (string_pos_list_of_expr_path_raise e) in + let types,filter_classes = ImportHandling.handle_using ctx path (pos e) in + (* Delay for #10107, but use delay_late to make sure base classes run before their children do. *) + delay_late ctx.g PConnectField (fun () -> + ti.mt_using <- (filter_classes types) @ ti.mt_using + ) + with Exit -> + raise_typing_error "dot path expected" (pos e) + ) el; + | _ -> + () + in + List.iter apply_using ti.mt_meta; (match f_enum with None -> () | Some f -> f()) let create_class_context c p = diff --git a/tests/misc/projects/Issue11625/Macro.hx b/tests/misc/projects/Issue11625/Macro.hx new file mode 100644 index 00000000000..f4cd459cbd3 --- /dev/null +++ b/tests/misc/projects/Issue11625/Macro.hx @@ -0,0 +1,5 @@ +function build() { + var cls = haxe.macro.Context.getLocalClass().get(); + cls.meta.add(":using", [macro Main.Extensions], cls.pos); + return null; +} diff --git a/tests/misc/projects/Issue11625/Main.hx b/tests/misc/projects/Issue11625/Main.hx new file mode 100644 index 00000000000..aa17ed4e317 --- /dev/null +++ b/tests/misc/projects/Issue11625/Main.hx @@ -0,0 +1,10 @@ +function main() { + Foo.test(); +} + +class Extensions { + public static function test(c:Class) trace("ok"); +} + +@:build(Macro.build()) +class Foo {} diff --git a/tests/misc/projects/Issue11625/compile.hxml b/tests/misc/projects/Issue11625/compile.hxml new file mode 100644 index 00000000000..42409e72918 --- /dev/null +++ b/tests/misc/projects/Issue11625/compile.hxml @@ -0,0 +1 @@ +-main Main From 8ec4f09bedbc8c0304e6de8008deff6022be380d Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Fri, 5 Apr 2024 08:42:09 +0200 Subject: [PATCH 36/49] Add support for binary literal (#11627) * Add support for binary literal * [tests] add tests for binary literal --- src/core/texpr.ml | 1 + src/syntax/lexer.ml | 5 +++++ tests/unit/src/unit/TestMisc.hx | 13 +++++++++++++ tests/unit/src/unit/TestNumericSeparator.hx | 12 ++++++++++++ tests/unit/src/unit/TestNumericSuffixes.hx | 10 +++++++++- 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/core/texpr.ml b/src/core/texpr.ml index e089d306197..558b8c963fe 100644 --- a/src/core/texpr.ml +++ b/src/core/texpr.ml @@ -612,6 +612,7 @@ let type_constant basic c p = match c with | Int (s,_) -> if String.length s > 10 && String.sub s 0 2 = "0x" then raise_typing_error "Invalid hexadecimal integer" p; + if String.length s > 34 && String.sub s 0 2 = "0b" then raise_typing_error "Invalid binary integer" p; (try mk (TConst (TInt (Int32.of_string s))) basic.tint p with _ -> mk (TConst (TFloat s)) basic.tfloat p) | Float (f,_) -> mk (TConst (TFloat f)) basic.tfloat p diff --git a/src/syntax/lexer.ml b/src/syntax/lexer.ml index abcfe8547bd..c3deee69db9 100644 --- a/src/syntax/lexer.ml +++ b/src/syntax/lexer.ml @@ -360,6 +360,9 @@ let integer_digits = [%sedlex.regexp? (digit, Star sep_digit)] let hex_digit = [%sedlex.regexp? '0'..'9'|'a'..'f'|'A'..'F'] let sep_hex_digit = [%sedlex.regexp? Opt '_', hex_digit] let hex_digits = [%sedlex.regexp? (hex_digit, Star sep_hex_digit)] +let bin_digit = [%sedlex.regexp? '0'|'1'] +let sep_bin_digit = [%sedlex.regexp? Opt '_', bin_digit] +let bin_digits = [%sedlex.regexp? (bin_digit, Star sep_bin_digit)] let integer = [%sedlex.regexp? ('1'..'9', Star sep_digit) | '0'] let integer_suffix = [%sedlex.regexp? Opt '_', ('i'|'u'), Plus integer] @@ -386,6 +389,8 @@ let rec token lexbuf = | '\n' | '\r' -> newline lexbuf; token lexbuf | "0x", Plus hex_digits, Opt integer_suffix -> mk lexbuf (split_int_suffix (lexeme lexbuf)) + | "0b", Plus bin_digits, Opt integer_suffix -> + mk lexbuf (split_int_suffix (lexeme lexbuf)) | integer, Opt integer_suffix -> mk lexbuf (split_int_suffix (lexeme lexbuf)) | integer, float_suffix -> diff --git a/tests/unit/src/unit/TestMisc.hx b/tests/unit/src/unit/TestMisc.hx index 12750493311..a4135266e6e 100644 --- a/tests/unit/src/unit/TestMisc.hx +++ b/tests/unit/src/unit/TestMisc.hx @@ -613,4 +613,17 @@ class TestMisc extends Test { var values = AbstractEnumTools.getValues(MyEnumAbstract); eq(values.join(","), "1,2,3"); } + + function testIntLiterals() { + eq(15, 0xF); + eq(255, 0xFF); + eq(305419896, 0x12345678); + eq(162254319, 0x09ABCDEF); + + eq(0, 0b0); + eq(1, 0b1); + eq(2, 0b10); + eq(8, 0b1000); + eq(0xFFFFFFFF, 0b11111111111111111111111111111111); + } } diff --git a/tests/unit/src/unit/TestNumericSeparator.hx b/tests/unit/src/unit/TestNumericSeparator.hx index 4cf3bf53bdb..5e3dda62618 100644 --- a/tests/unit/src/unit/TestNumericSeparator.hx +++ b/tests/unit/src/unit/TestNumericSeparator.hx @@ -10,6 +10,10 @@ class TestNumericSeparator extends Test { eq(0x12_0, 0x120); eq(0x1_2_0, 0x120); + // bin int + eq(0b11_0, 0b110); + eq(0b1_1_0, 0b110); + // normal float feq(12.3_4, 12.34); feq(1_2.34, 12.34); @@ -36,6 +40,10 @@ class TestNumericSeparator extends Test { eq(0x12_0i32, 0x120i32); eq(0x1_2_0i32, 0x120i32); + // bin int + eq(0b11_0i32, 0b110i32); + eq(0b1_1_0i32, 0b110i32); + // normal float feq(12.3_4f64, 12.34f64); feq(1_2.34f64, 12.34f64); @@ -59,6 +67,10 @@ class TestNumericSeparator extends Test { eq(0x12_0_i32, 0x120i32); eq(0x1_2_0_i32, 0x120i32); + // bin int + eq(0b11_0_i32, 0b110i32); + eq(0b1_1_0_i32, 0b110i32); + // normal float feq(12.3_4_f64, 12.34f64); feq(1_2.34_f64, 12.34f64); diff --git a/tests/unit/src/unit/TestNumericSuffixes.hx b/tests/unit/src/unit/TestNumericSuffixes.hx index ef651805727..745f4be39a1 100644 --- a/tests/unit/src/unit/TestNumericSuffixes.hx +++ b/tests/unit/src/unit/TestNumericSuffixes.hx @@ -26,4 +26,12 @@ class TestNumericSuffixes extends Test { eq(0xFFFFFFFFFFFFFFFFi64 + "", "-1"); eq(0x7FFFFFFFFFFFFFFFi64 + "", "9223372036854775807"); } -} \ No newline at end of file + + public function testBinSuffixes() { + eq(0b11111111111111111111111111111111i32, -1); + eq(0b11111111111111111111111111111111u32, (0b11111111111111111111111111111111i32 : UInt)); + eq(0b11111111111111111111111111111111i64 + "", "4294967295"); + eq(0b1111111111111111111111111111111111111111111111111111111111111111i64 + "", "-1"); + eq(0b0111111111111111111111111111111111111111111111111111111111111111i64 + "", "9223372036854775807"); + } +} From c64f5ca4a61b0334ffdb9f504a0c37043bb4e6b8 Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Fri, 5 Apr 2024 11:28:04 +0200 Subject: [PATCH 37/49] [hl] Fix NotEq compare nullInt with Int (#11629) * [hl] Fix NotEq compare nullInt with Int * [tests] Prevent analyser run on TestOps * [tests] disable analyzer only on some functions --- src/generators/genhl.ml | 9 +++++++-- tests/unit/src/unit/TestOps.hx | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index 906269742f1..aa60213418f 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -1491,6 +1491,11 @@ and jump_expr ctx e jcond = | OpNotEq -> if jcond then OJNotEq (r1,r2,i) else OJEq (r1,r2,i) | _ -> die "" __LOC__ ) in + let nullisfalse = match jop with + | OpEq -> jcond + | OpNotEq -> not jcond + | _ -> die "" __LOC__ + in let t1 = to_type ctx e1.etype in let t2 = to_type ctx e2.etype in (match t1, t2 with @@ -1510,8 +1515,8 @@ and jump_expr ctx e jcond = free ctx a; free ctx r1; let j = jumpeq a b in - if jcond then (jnull();); - (fun() -> if not jcond then (jnull();); j()); + if nullisfalse then (jnull();); + (fun() -> if not nullisfalse then (jnull();); j()); | _ -> let t = common_type ctx e1 e2 true e.epos in let a = eval_to ctx e1 t in diff --git a/tests/unit/src/unit/TestOps.hx b/tests/unit/src/unit/TestOps.hx index 474c1aff894..5c00338a54c 100644 --- a/tests/unit/src/unit/TestOps.hx +++ b/tests/unit/src/unit/TestOps.hx @@ -103,6 +103,7 @@ class TestOps extends Test { #if target.static + @:analyzer(ignore) function testNullOps() { var a:Null = 10; // arithmetic @@ -163,6 +164,7 @@ class TestOps extends Test { #if !flash // Will not fix for flash + @:analyzer(ignore) function testNadakoOps() { // bool var nullBool:Null = null; @@ -257,6 +259,7 @@ class TestOps extends Test { #end + @:analyzer(ignore) function testDynamicOps() { var a:Dynamic = 10; // arithmetic From 76b36356b2f79de32731d6cfbcec58f85cd80562 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Fri, 5 Apr 2024 15:58:14 +0200 Subject: [PATCH 38/49] [eval] remove more hlmacro leftovers --- src/generators/hlinterp.ml | 9 --------- std/haxe/macro/Compiler.hx | 3 --- std/haxe/macro/MacroStringTools.hx | 3 --- std/haxe/macro/TypeTools.hx | 3 --- 4 files changed, 18 deletions(-) diff --git a/src/generators/hlinterp.ml b/src/generators/hlinterp.ml index 8c32aced375..6ef4201842b 100644 --- a/src/generators/hlinterp.ml +++ b/src/generators/hlinterp.ml @@ -113,7 +113,6 @@ type context = { mutable fcall : vfunction -> value list -> value; mutable code : code; mutable on_error : value -> (fundecl * int ref) list -> unit; - mutable resolve_macro_api : string -> (value list -> value) option; checked : bool; cached_protos : (int, vproto * ttype array * (int * (value -> value)) list) Hashtbl.t; cached_strings : (int, string) Hashtbl.t; @@ -2094,10 +2093,6 @@ let load_native ctx lib name t = | _ -> Globals.die "" __LOC__) | _ -> unresolved()) - | "macro" -> - (match ctx.resolve_macro_api name with - | None -> unresolved() - | Some f -> f) | _ -> unresolved() ) in @@ -2130,7 +2125,6 @@ let create checked = checked = checked; fcall = (fun _ _ -> Globals.die "" __LOC__); on_error = (fun _ _ -> Globals.die "" __LOC__); - resolve_macro_api = (fun _ -> None); } in ctx.on_error <- (fun msg stack -> failwith (vstr ctx msg HDyn ^ "\n" ^ String.concat "\n" (List.map (stack_frame ctx) stack))); ctx.fcall <- call_fun ctx; @@ -2139,9 +2133,6 @@ let create checked = let set_error_handler ctx e = ctx.on_error <- e -let set_macro_api ctx f = - ctx.resolve_macro_api <- f - let add_code ctx code = (* expand global table *) let globals = Array.map default code.globals in diff --git a/std/haxe/macro/Compiler.hx b/std/haxe/macro/Compiler.hx index 910985557f2..cc3e5d14aec 100644 --- a/std/haxe/macro/Compiler.hx +++ b/std/haxe/macro/Compiler.hx @@ -29,9 +29,6 @@ import haxe.hxb.WriterConfig; /** All these methods can be called for compiler configuration macros. **/ -#if hl -@:hlNative("macro") -#end class Compiler { /** A conditional compilation flag can be set on the command line using diff --git a/std/haxe/macro/MacroStringTools.hx b/std/haxe/macro/MacroStringTools.hx index bfd422e4eb0..4922a6f0d9b 100644 --- a/std/haxe/macro/MacroStringTools.hx +++ b/std/haxe/macro/MacroStringTools.hx @@ -28,9 +28,6 @@ import haxe.macro.Expr; This class provides some utility methods to work with strings in macro context. **/ -#if hl -@:hlNative("macro") -#end class MacroStringTools { #if macro /** diff --git a/std/haxe/macro/TypeTools.hx b/std/haxe/macro/TypeTools.hx index 57d8b25b782..38949bf172f 100644 --- a/std/haxe/macro/TypeTools.hx +++ b/std/haxe/macro/TypeTools.hx @@ -33,9 +33,6 @@ using Lambda; best used through 'using haxe.macro.TypeTools' syntax and then provides additional methods on haxe.macro.Type instances. **/ -#if hl -@:hlNative("macro") -#end class TypeTools { static function nullable(complexType:ComplexType):ComplexType return macro:Null<$complexType>; From 323d2c494e1a4553eb923abc6ae8cfc0f337f82d Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Tue, 9 Apr 2024 11:24:18 +0200 Subject: [PATCH 39/49] [macro] catch unexpected null type --- src/macro/macroApi.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index 22686caa6bf..50bc9333d45 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -846,6 +846,7 @@ and decode_field v = } and decode_ctype t = + if t = vnull then raise Invalid_expr; let (i,args),p = decode_enum_with_pos t in (match i,args with | 0, [p] -> From 72175301c3dbd3eaa70f3479e6e46cb620242eef Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Tue, 9 Apr 2024 18:05:38 +0200 Subject: [PATCH 40/49] [macro] Catch eval runtime failures when decoding (#11633) * [eval] Catch runtime exceptions in safe_decode * [macro] narrow build macro eval failures to individual field (hacky...) * [tests] add test for 11632 * Less hacky way to retrieve haxe.macro.Field type * [tests] remove unneeded import --- src/macro/macroApi.ml | 1 - src/typing/macroContext.ml | 17 ++++++++++++----- tests/misc/projects/Issue11632/Main.hx | 15 +++++++++++++++ tests/misc/projects/Issue11632/Test.hx | 6 ++++++ .../misc/projects/Issue11632/compile-fail.hxml | 1 + .../Issue11632/compile-fail.hxml.stderr | 1 + .../misc/projects/Issue11632/compile-test.hxml | 1 + .../Issue11632/compile-test.hxml.stdout | 14 ++++++++++++++ 8 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 tests/misc/projects/Issue11632/Main.hx create mode 100644 tests/misc/projects/Issue11632/Test.hx create mode 100644 tests/misc/projects/Issue11632/compile-fail.hxml create mode 100644 tests/misc/projects/Issue11632/compile-fail.hxml.stderr create mode 100644 tests/misc/projects/Issue11632/compile-test.hxml create mode 100644 tests/misc/projects/Issue11632/compile-test.hxml.stdout diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index 50bc9333d45..22686caa6bf 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -846,7 +846,6 @@ and decode_field v = } and decode_ctype t = - if t = vnull then raise Invalid_expr; let (i,args),p = decode_enum_with_pos t in (match i,args with | 0, [p] -> diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index 7f428adb155..84c66b004b2 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -41,15 +41,20 @@ module HxbWriterConfigWriterEval = HxbWriterConfig.WriterConfigWriter(EvalDataAp let macro_interp_cache = ref None let safe_decode com v expected t p f = - try - f () - with MacroApi.Invalid_expr -> + let raise_decode_error s = let path = [dump_path com;"decoding_error"] in let ch = Path.create_file false ".txt" [] path in let errors = Interp.handle_decoding_error (output_string ch) v t in List.iter (fun (s,i) -> Printf.fprintf ch "\nline %i: %s" i s) (List.rev errors); close_out ch; - raise_typing_error (Printf.sprintf "Expected %s but got %s (see %s.txt for details)" expected (Interp.value_string v) (String.concat "/" path)) p + raise_typing_error (Printf.sprintf "%s (see %s.txt for details)" s (String.concat "/" path)) p + in + + try f () with + | EvalContext.RunTimeException (VString emsg,_,_) -> + raise_decode_error (Printf.sprintf "Eval runtime exception: %s" emsg.sstring) + | MacroApi.Invalid_expr -> + raise_decode_error (Printf.sprintf "Expected %s but got %s" expected (Interp.value_string v)) let macro_timer com l = @@ -960,7 +965,9 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p = | None -> die "" __LOC__ | Some (_,_,fields) -> fields) else - List.map Interp.decode_field (Interp.decode_array v) + let ct = make_ptp_th (mk_type_path ~sub:"Field" (["haxe";"macro"], "Expr")) null_pos in + let t = Typeload.load_complex_type mctx false LoadNormal ct in + List.map (fun f -> safe_decode ctx.com f "Field" t p (fun () -> Interp.decode_field f)) (Interp.decode_array v) in MSuccess (EVars [mk_evar ~t:(CTAnonymous fields,p) ("fields",null_pos)],p) ) diff --git a/tests/misc/projects/Issue11632/Main.hx b/tests/misc/projects/Issue11632/Main.hx new file mode 100644 index 00000000000..c49eedc91f7 --- /dev/null +++ b/tests/misc/projects/Issue11632/Main.hx @@ -0,0 +1,15 @@ +#if macro +import haxe.macro.Expr; +#end + +#if !macro @:build(Macro.build()) #end +class Main {} + +class Macro { + public static function build() { + var ct = TPath({pack: [], name: "Null", params: [TPType(null)]}); + return (macro class { + var foo:$ct; + }).fields; + } +} diff --git a/tests/misc/projects/Issue11632/Test.hx b/tests/misc/projects/Issue11632/Test.hx new file mode 100644 index 00000000000..fcc7db404d9 --- /dev/null +++ b/tests/misc/projects/Issue11632/Test.hx @@ -0,0 +1,6 @@ +import sys.io.File; + +function main() { + var dump = File.getContent("dump/decoding_error.txt"); + Sys.println(dump); +} diff --git a/tests/misc/projects/Issue11632/compile-fail.hxml b/tests/misc/projects/Issue11632/compile-fail.hxml new file mode 100644 index 00000000000..20afe58fbc6 --- /dev/null +++ b/tests/misc/projects/Issue11632/compile-fail.hxml @@ -0,0 +1 @@ +--main Main diff --git a/tests/misc/projects/Issue11632/compile-fail.hxml.stderr b/tests/misc/projects/Issue11632/compile-fail.hxml.stderr new file mode 100644 index 00000000000..b329610445d --- /dev/null +++ b/tests/misc/projects/Issue11632/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:5: characters 12-19 : Eval runtime exception: Null Access (see dump/decoding_error.txt for details) diff --git a/tests/misc/projects/Issue11632/compile-test.hxml b/tests/misc/projects/Issue11632/compile-test.hxml new file mode 100644 index 00000000000..34c9a3273df --- /dev/null +++ b/tests/misc/projects/Issue11632/compile-test.hxml @@ -0,0 +1 @@ +--run Test diff --git a/tests/misc/projects/Issue11632/compile-test.hxml.stdout b/tests/misc/projects/Issue11632/compile-test.hxml.stdout new file mode 100644 index 00000000000..29b199f8d88 --- /dev/null +++ b/tests/misc/projects/Issue11632/compile-test.hxml.stdout @@ -0,0 +1,14 @@ +{ + access: null + doc: null + kind: FVar(TPath({ + name: Null + pack: [] + params: [TPType(null <- expected enum value)] + sub: null + }), null) + meta: null + name: foo + pos: #pos +} +line 7: expected enum value From 569e52e64c18b4fbb44268dcdaaac647eab051f8 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 11 Apr 2024 10:08:44 +0200 Subject: [PATCH 41/49] Add pos to generated @:value metadata --- src/typing/typeloadFields.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index 92f67fef2e6..136bc81d484 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -737,7 +737,7 @@ module TypeBinding = struct let p = cf.cf_pos in let ctx = TyperManager.clone_for_expr ctx_f (if fctx.is_static then FunStatic else FunMember) false in if (has_class_flag c CInterface) then unexpected_expression ctx.com fctx "Initialization on field of interface" (pos e); - cf.cf_meta <- ((Meta.Value,[e],null_pos) :: cf.cf_meta); + cf.cf_meta <- ((Meta.Value,[e],cf.cf_pos) :: cf.cf_meta); let check_cast e = (* insert cast to keep explicit field type (issue #1901) *) if type_iseq e.etype cf.cf_type then From ed138ae917db80ef342bed416f2543a34b9d27be Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 18 Apr 2024 14:59:59 +0200 Subject: [PATCH 42/49] [macro] apply @:native for extern enum (#11636) * [eval] apply @:native for externs * [macro] only apply @:native for extern enums * Add tabstract.a_extern * [macro] apply @:native to extern enum and extern enum abstract * [tests] update test for 11481 * [tests] add test for 11631 * [hxb] add a_extern --- src/compiler/hxb/hxbReader.ml | 1 + src/compiler/hxb/hxbWriter.ml | 1 + src/core/tFunctions.ml | 1 + src/core/tOther.ml | 28 +------------------ src/core/tType.ml | 1 + src/typing/macroContext.ml | 10 +++++++ src/typing/typeloadModule.ml | 1 + tests/misc/projects/Issue11481/Main.hx | 6 +++- .../projects/Issue11481/compile.hxml.stdout | 5 +++- .../misc/projects/Issue11481/pack/OldClass.hx | 9 +++--- .../Issue11481/pack/OldEnumAbstract.hx | 16 +++++++++++ tests/misc/projects/Issue11631/Main.hx | 6 ++++ tests/misc/projects/Issue11631/Main.macro.hx | 4 +++ tests/misc/projects/Issue11631/compile.hxml | 2 ++ .../projects/Issue11631/compile.hxml.stdout | 2 ++ 15 files changed, 60 insertions(+), 33 deletions(-) create mode 100644 tests/misc/projects/Issue11481/pack/OldEnumAbstract.hx create mode 100644 tests/misc/projects/Issue11631/Main.hx create mode 100644 tests/misc/projects/Issue11631/Main.macro.hx create mode 100644 tests/misc/projects/Issue11631/compile.hxml create mode 100644 tests/misc/projects/Issue11631/compile.hxml.stdout diff --git a/src/compiler/hxb/hxbReader.ml b/src/compiler/hxb/hxbReader.ml index f85b67218d8..4d9ddfbcb29 100644 --- a/src/compiler/hxb/hxbReader.ml +++ b/src/compiler/hxb/hxbReader.ml @@ -1515,6 +1515,7 @@ class hxb_reader end; a.a_from <- self#read_list (fun () -> self#read_type_instance); a.a_to <- self#read_list (fun () -> self#read_type_instance); + a.a_extern <- self#read_bool; a.a_enum <- self#read_bool; method read_abstract_fields (a : tabstract) = diff --git a/src/compiler/hxb/hxbWriter.ml b/src/compiler/hxb/hxbWriter.ml index d0358465963..723b7d91aa0 100644 --- a/src/compiler/hxb/hxbWriter.ml +++ b/src/compiler/hxb/hxbWriter.ml @@ -1925,6 +1925,7 @@ module HxbWriter = struct end; Chunk.write_list writer.chunk a.a_from (write_type_instance writer); Chunk.write_list writer.chunk a.a_to (write_type_instance writer); + Chunk.write_bool writer.chunk a.a_extern; Chunk.write_bool writer.chunk a.a_enum let write_abstract_fields writer (a : tabstract) = diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index cdb457a8923..afbe64b7294 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -286,6 +286,7 @@ let null_abstract = { a_read = None; a_write = None; a_call = None; + a_extern = false; a_enum = false; } diff --git a/src/core/tOther.ml b/src/core/tOther.ml index c3b221418ff..13c5d1e8fcf 100644 --- a/src/core/tOther.ml +++ b/src/core/tOther.ml @@ -280,33 +280,6 @@ let mk_enum m path pos name_pos = e_type = mk_mono(); } -let mk_abstract m path pos name_pos = - { - a_path = path; - a_private = false; - a_module = m; - a_pos = pos; - a_name_pos = name_pos; - a_doc = None; - a_params = []; - a_using = []; - a_restore = (fun () -> ()); - a_meta = []; - a_from = []; - a_to = []; - a_from_field = []; - a_to_field = []; - a_ops = []; - a_unops = []; - a_impl = None; - a_array = []; - a_this = mk_mono(); - a_read = None; - a_write = None; - a_enum = false; - a_call = None; - } - let mk_enum m path pos name_pos = { e_path = path; @@ -348,6 +321,7 @@ let mk_abstract m path pos name_pos = a_this = mk_mono(); a_read = None; a_write = None; + a_extern = false; a_enum = false; a_call = None; } diff --git a/src/core/tType.ml b/src/core/tType.ml index 7d6259285a2..b7122360cf5 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -377,6 +377,7 @@ and tabstract = { mutable a_read : tclass_field option; mutable a_write : tclass_field option; mutable a_call : tclass_field option; + mutable a_extern : bool; mutable a_enum : bool; } diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index 84c66b004b2..260fdda1b52 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -632,12 +632,22 @@ and flush_macro_context mint mctx = | _ -> () in + (* Apply native paths for externs only *) + let maybe_apply_native_paths t = + let apply_native = match t with + | TClassDecl { cl_kind = KAbstractImpl a } -> a.a_extern && a.a_enum + | TEnumDecl e -> e.e_extern + | _ -> false + in + if apply_native then Naming.apply_native_paths t + in let type_filters = [ FiltersCommon.remove_generic_base; Exceptions.patch_constructors mctx; (fun mt -> AddFieldInits.add_field_inits mctx.c.curclass.cl_path (RenameVars.init mctx.com) mctx.com mt); Filters.update_cache_dependencies ~close_monomorphs:false mctx.com; minimal_restore; + maybe_apply_native_paths ] in let ready = fun t -> FiltersCommon.apply_filters_once mctx expr_filters t; diff --git a/src/typing/typeloadModule.ml b/src/typing/typeloadModule.ml index 1d66ea81909..b340492ee06 100644 --- a/src/typing/typeloadModule.ml +++ b/src/typing/typeloadModule.ml @@ -198,6 +198,7 @@ module ModuleLevel = struct a_read = None; a_write = None; a_call = None; + a_extern = List.mem AbExtern d.d_flags; a_enum = List.mem AbEnum d.d_flags || p_enum_meta <> None; } in begin match p_enum_meta with diff --git a/tests/misc/projects/Issue11481/Main.hx b/tests/misc/projects/Issue11481/Main.hx index 4d95c5f0be2..116727aeefb 100644 --- a/tests/misc/projects/Issue11481/Main.hx +++ b/tests/misc/projects/Issue11481/Main.hx @@ -1,3 +1,7 @@ function main() { + pack.OldClass.f1(); + pack.OldEnumAbstract.f1(); + trace(pack.OldClass); -} \ No newline at end of file + trace(pack.OldEnumAbstract.SSL_TRANSPORT_STREAM); +} diff --git a/tests/misc/projects/Issue11481/compile.hxml.stdout b/tests/misc/projects/Issue11481/compile.hxml.stdout index a4310c6c4f8..c4bfb0a46fb 100644 --- a/tests/misc/projects/Issue11481/compile.hxml.stdout +++ b/tests/misc/projects/Issue11481/compile.hxml.stdout @@ -1 +1,4 @@ -Main.hx:2: Class \ No newline at end of file +pack/OldClass.hx:10: Class +pack/OldEnumAbstract.hx:13: 0 +Main.hx:5: Class +Main.hx:6: 0 diff --git a/tests/misc/projects/Issue11481/pack/OldClass.hx b/tests/misc/projects/Issue11481/pack/OldClass.hx index 163b567c747..c9c831eb3a7 100644 --- a/tests/misc/projects/Issue11481/pack/OldClass.hx +++ b/tests/misc/projects/Issue11481/pack/OldClass.hx @@ -3,10 +3,11 @@ package pack; @:native("NewClass") class OldClass { macro static function f2() { - return null; + return macro null; } - macro static function f1() { - return null; + public macro static function f1() { + trace(OldClass); + return macro null; } -} \ No newline at end of file +} diff --git a/tests/misc/projects/Issue11481/pack/OldEnumAbstract.hx b/tests/misc/projects/Issue11481/pack/OldEnumAbstract.hx new file mode 100644 index 00000000000..d0246e29b44 --- /dev/null +++ b/tests/misc/projects/Issue11481/pack/OldEnumAbstract.hx @@ -0,0 +1,16 @@ +package pack; + +@:native("mbedtls.SslTransport") +extern enum abstract OldEnumAbstract(Int) { + var SSL_TRANSPORT_STREAM; + var SSL_TRANSPORT_DATAGRAM; + + macro static function f2() { + return macro null; + } + + public macro static function f1() { + trace(SSL_TRANSPORT_STREAM); + return macro null; + } +} diff --git a/tests/misc/projects/Issue11631/Main.hx b/tests/misc/projects/Issue11631/Main.hx new file mode 100644 index 00000000000..0b2f8ea5f81 --- /dev/null +++ b/tests/misc/projects/Issue11631/Main.hx @@ -0,0 +1,6 @@ +function main() { + trace(mbedtls.SslTransport.SSL_TRANSPORT_STREAM); + test(); +} + +macro function test(); diff --git a/tests/misc/projects/Issue11631/Main.macro.hx b/tests/misc/projects/Issue11631/Main.macro.hx new file mode 100644 index 00000000000..4aeff142b7e --- /dev/null +++ b/tests/misc/projects/Issue11631/Main.macro.hx @@ -0,0 +1,4 @@ +macro function test() { + trace(mbedtls.SslTransport.SSL_TRANSPORT_STREAM); + return macro {}; +} diff --git a/tests/misc/projects/Issue11631/compile.hxml b/tests/misc/projects/Issue11631/compile.hxml new file mode 100644 index 00000000000..d9ece4a40bb --- /dev/null +++ b/tests/misc/projects/Issue11631/compile.hxml @@ -0,0 +1,2 @@ +-m Main +--interp diff --git a/tests/misc/projects/Issue11631/compile.hxml.stdout b/tests/misc/projects/Issue11631/compile.hxml.stdout new file mode 100644 index 00000000000..36deb498bc4 --- /dev/null +++ b/tests/misc/projects/Issue11631/compile.hxml.stdout @@ -0,0 +1,2 @@ +Main.macro.hx:2: 0 +Main.hx:2: 0 From db842bfd6c815784f16da415d6718bcb7d393a66 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 18 Apr 2024 15:00:36 +0200 Subject: [PATCH 43/49] Cleanup error positions (#11630) * Add and use file_pos and fake_pos instead of manually creating pos objects * [Pretty errors] Don't try to display position source when pos points to file itself * [tests] update tests --- src/codegen/javaModern.ml | 12 +-- src/codegen/swfLoader.ml | 2 +- src/compiler/args.ml | 2 +- src/compiler/compiler.ml | 2 +- src/compiler/displayProcessing.ml | 2 +- src/compiler/hxb/hxbWriter.ml | 2 +- src/compiler/messageReporting.ml | 92 ++++++++++--------- src/context/commonCache.ml | 2 +- src/context/display/displayPath.ml | 2 +- src/context/display/documentSymbols.ml | 2 +- src/core/globals.ml | 4 +- src/macro/eval/evalDebugSocket.ml | 2 +- src/typing/macroContext.ml | 2 +- src/typing/typeloadParse.ml | 2 +- .../Issue8303/pretty-fail.hxml.stderr | 4 +- 15 files changed, 65 insertions(+), 69 deletions(-) diff --git a/src/codegen/javaModern.ml b/src/codegen/javaModern.ml index 8fbd3cb81b6..e03926e85a3 100644 --- a/src/codegen/javaModern.ml +++ b/src/codegen/javaModern.ml @@ -754,11 +754,7 @@ module Converter = struct tp let convert_enum (jc : jclass) (file : string) = - let p = { - pfile = file; - pmin = 0; - pmax = 0 - } in + let p = file_pos file in let meta = ref [] in let add_meta m = meta := m :: !meta in let data = ref [] in @@ -920,11 +916,7 @@ module Converter = struct cff let convert_class ctx (jc : jclass) (file : string) = - let p = { - pfile = file; - pmin = 0; - pmax = 0 - } in + let p = file_pos file in let flags = ref [HExtern] in let meta = ref [] in let add_flag f = flags := f :: !flags in diff --git a/src/codegen/swfLoader.ml b/src/codegen/swfLoader.ml index fe0e05b8268..fa9ba999f0d 100644 --- a/src/codegen/swfLoader.ml +++ b/src/codegen/swfLoader.ml @@ -147,7 +147,7 @@ let is_valid_path com pack name = let build_class com c file = let path = (make_tpath c.hlc_name).path in - let pos = { pfile = file ^ "@" ^ s_type_path (path.tpackage,path.tname); pmin = 0; pmax = 0 } in + let pos = file_pos (file ^ "@" ^ s_type_path (path.tpackage,path.tname)) in match path with | { tpackage = ["flash";"utils"]; tname = ("Object"|"Function") } -> let inf = { diff --git a/src/compiler/args.ml b/src/compiler/args.ml index c3de78ce41e..3f95944aa54 100644 --- a/src/compiler/args.ml +++ b/src/compiler/args.ml @@ -293,7 +293,7 @@ let parse_args com = ),"","set current working directory"); ("Compilation",["--haxelib-global"],[], Arg.Unit (fun () -> ()),"","pass --global argument to haxelib"); ("Compilation",["-w"],[], Arg.String (fun s -> - let p = { pfile = "-w " ^ s; pmin = 0; pmax = 0 } in + let p = fake_pos ("-w " ^ s) in let l = Warning.parse_options s p in com.warning_options <- l :: com.warning_options ),"","enable or disable specific warnings"); diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index f780a042459..57c89dae094 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -275,7 +275,7 @@ let check_defines com = PMap.iter (fun k _ -> try let reason = Hashtbl.find Define.deprecation_lut k in - let p = { pfile = "-D " ^ k; pmin = -1; pmax = -1 } in + let p = fake_pos ("-D " ^ k) in com.warning WDeprecatedDefine [] reason p with Not_found -> () diff --git a/src/compiler/displayProcessing.ml b/src/compiler/displayProcessing.ml index 7e345a0f8e6..fc3ea076fdc 100644 --- a/src/compiler/displayProcessing.ml +++ b/src/compiler/displayProcessing.ml @@ -244,7 +244,7 @@ let load_display_file_standalone (ctx : Typecore.typer) file = let load_display_content_standalone (ctx : Typecore.typer) input = let com = ctx.com in let file = file_input_marker in - let p = {pfile = file; pmin = 0; pmax = 0} in + let p = file_pos file in let parsed = TypeloadParse.parse_file_from_string com file p input in let pack,decls = TypeloadParse.handle_parser_result com p parsed in ignore(TypeloadModule.type_module ctx.com ctx.g (pack,"?DISPLAY") file ~dont_check_path:true decls p) diff --git a/src/compiler/hxb/hxbWriter.ml b/src/compiler/hxb/hxbWriter.ml index 723b7d91aa0..222cff951b4 100644 --- a/src/compiler/hxb/hxbWriter.ml +++ b/src/compiler/hxb/hxbWriter.ml @@ -1122,7 +1122,7 @@ module HxbWriter = struct end with Not_found -> (try ignore(IdentityPool.get writer.unbound_ttp ttp) with Not_found -> begin ignore(IdentityPool.add writer.unbound_ttp ttp ()); - let p = { null_pos with pfile = (Path.UniqueKey.lazy_path writer.current_module.m_extra.m_file) } in + let p = file_pos (Path.UniqueKey.lazy_path writer.current_module.m_extra.m_file) in let msg = Printf.sprintf "Unbound type parameter %s" (s_type_path ttp.ttp_class.cl_path) in writer.warn WUnboundTypeParameter msg p end); diff --git a/src/compiler/messageReporting.ml b/src/compiler/messageReporting.ml index f7f76d31123..2d9ecc80f3e 100644 --- a/src/compiler/messageReporting.ml +++ b/src/compiler/messageReporting.ml @@ -4,54 +4,57 @@ open Common open CompilationContext let resolve_source file l1 p1 l2 p2 = - let ch = open_in_bin file in - let curline = ref 1 in - let lines = ref [] in - let rec loop p line = - let inc i line = - if (!curline >= l1) && (!curline <= l2) then lines := (!curline, line) :: !lines; - curline := !curline + 1; - (i, "") - in - - let input_char_or_done ch line = - try input_char ch with End_of_file -> begin - ignore(inc 0 line); - raise End_of_file - end - in + if l1 = l2 && p1 = p2 && l1 = 1 && p1 = 1 then [] + else begin + let ch = open_in_bin file in + let curline = ref 1 in + let lines = ref [] in + let rec loop p line = + let inc i line = + if (!curline >= l1) && (!curline <= l2) then lines := (!curline, line) :: !lines; + curline := !curline + 1; + (i, "") + in - let read_char line = match input_char_or_done ch line with - | '\n' -> inc 1 line - | '\r' -> - ignore(input_char_or_done ch line); - inc 2 line - | c -> begin - let line = ref (line ^ (String.make 1 c)) in - let rec skip n = - if n > 0 then begin - let c = input_char_or_done ch !line in - line := !line ^ (String.make 1 c); - skip (n - 1) - end - in + let input_char_or_done ch line = + try input_char ch with End_of_file -> begin + ignore(inc 0 line); + raise End_of_file + end + in - let code = int_of_char c in - if code < 0xC0 then () - else if code < 0xE0 then skip 1 - else if code < 0xF0 then skip 2 - else skip 3; + let read_char line = match input_char_or_done ch line with + | '\n' -> inc 1 line + | '\r' -> + ignore(input_char_or_done ch line); + inc 2 line + | c -> begin + let line = ref (line ^ (String.make 1 c)) in + let rec skip n = + if n > 0 then begin + let c = input_char_or_done ch !line in + line := !line ^ (String.make 1 c); + skip (n - 1) + end + in + + let code = int_of_char c in + if code < 0xC0 then () + else if code < 0xE0 then skip 1 + else if code < 0xF0 then skip 2 + else skip 3; + + (1, !line) + end + in - (1, !line) - end + let (delta, line) = read_char line in + loop (p + delta) line in - let (delta, line) = read_char line in - loop (p + delta) line - in - - try loop 0 ""; with End_of_file -> close_in ch; - List.rev !lines + try loop 0 ""; with End_of_file -> close_in ch; + List.rev !lines + end let resolve_file ctx f = let ext = StringHelper.extension f in @@ -100,7 +103,8 @@ let compiler_pretty_message_string com ectx cm = let l1, p1, l2, p2 = Lexer.get_pos_coords cm.cm_pos in let lines = resolve_source f l1 p1 l2 p2 in let epos = - if ectx.absolute_positions then TPrinting.Printer.s_pos cm.cm_pos + if lines = [] then cm.cm_pos.pfile + else if ectx.absolute_positions then TPrinting.Printer.s_pos cm.cm_pos else Lexer.get_error_pos error_printer cm.cm_pos in (l1, p1, l2, p2, epos, lines) diff --git a/src/context/commonCache.ml b/src/context/commonCache.ml index d2c7db7796c..a0c92924b55 100644 --- a/src/context/commonCache.ml +++ b/src/context/commonCache.ml @@ -11,7 +11,7 @@ class lib_build_task cs file ftime lib = object(self) let h = Hashtbl.create 0 in List.iter (fun path -> if not (Hashtbl.mem h path) then begin - let p = { pfile = file ^ " @ " ^ Globals.s_type_path path; pmin = 0; pmax = 0; } in + let p = file_pos (file ^ " @ " ^ Globals.s_type_path path) in try begin match lib#build path p with | Some r -> Hashtbl.add h path r | None -> () diff --git a/src/context/display/displayPath.ml b/src/context/display/displayPath.ml index 27c2cf784d9..e6c0c99f618 100644 --- a/src/context/display/displayPath.ml +++ b/src/context/display/displayPath.ml @@ -189,7 +189,7 @@ let handle_path_display ctx path p = (* We assume that we want to go to the module file, not a specific type which might not even exist anyway. *) let mt = ctx.g.do_load_module ctx (sl,s) p in - let p = { pfile = (Path.UniqueKey.lazy_path mt.m_extra.m_file); pmin = 0; pmax = 0} in + let p = file_pos (Path.UniqueKey.lazy_path mt.m_extra.m_file) in raise_positions [p] | (IDKModule(sl,s),_),DMHover -> let m = ctx.g.do_load_module ctx (sl,s) p in diff --git a/src/context/display/documentSymbols.ml b/src/context/display/documentSymbols.ml index 4d61a6ae4ef..d93c8b4fe92 100644 --- a/src/context/display/documentSymbols.ml +++ b/src/context/display/documentSymbols.ml @@ -114,7 +114,7 @@ let collect_module_symbols mname with_locals (pack,decls) = ) decls; begin match mname with | Some(file,mname) when not (Hashtbl.mem type_decls mname) -> - add mname Module {pfile = file; pmin = 0; pmax = 0} (String.concat "." pack) false + add mname Module (file_pos file) (String.concat "." pack) false | _ -> () end; diff --git a/src/core/globals.ml b/src/core/globals.ml index c7a557298c7..3c474d8512d 100644 --- a/src/core/globals.ml +++ b/src/core/globals.ml @@ -30,7 +30,9 @@ let version_minor = (version mod 1000) / 100 let version_revision = (version mod 100) let version_pre = Some "alpha.1" -let null_pos = { pfile = "?"; pmin = -1; pmax = -1 } +let file_pos file = { pfile = file; pmin = 0; pmax = 0 } +let fake_pos p = { pfile = p; pmin = -1; pmax = -1 } +let null_pos = fake_pos "?" let no_color = false let c_reset = if no_color then "" else "\x1b[0m" diff --git a/src/macro/eval/evalDebugSocket.ml b/src/macro/eval/evalDebugSocket.ml index 55be0d1cb98..880b66b651d 100644 --- a/src/macro/eval/evalDebugSocket.ml +++ b/src/macro/eval/evalDebugSocket.ml @@ -473,7 +473,7 @@ module ValueCompletion = struct exception JsonException of Json.t let get_completion ctx text column env = - let p = { pmin = 0; pmax = 0; pfile = "" } in + let p = file_pos "" in let save = let old = !Parser.display_mode,DisplayPosition.display_position#get in (fun () -> diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index 260fdda1b52..d9f307b2b0e 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -1010,7 +1010,7 @@ let call_macro mctx args margs call p = call (List.map (fun e -> try Interp.make_const e with Exit -> raise_typing_error "Argument should be a constant" e.epos) el) let resolve_init_macro com e = - let p = { pfile = "--macro " ^ e; pmin = -1; pmax = -1 } in + let p = fake_pos ("--macro " ^ e) in let e = try if String.get e (String.length e - 1) = ';' then raise_typing_error "Unexpected ;" p; begin match ParserEntry.parse_expr_string com.defines e p raise_typing_error false with diff --git a/src/typing/typeloadParse.ml b/src/typing/typeloadParse.ml index cfad8bff5f1..869a7f892b2 100644 --- a/src/typing/typeloadParse.ml +++ b/src/typing/typeloadParse.ml @@ -39,7 +39,7 @@ let parse_file_from_lexbuf com file p lexbuf = with | Sedlexing.MalFormed -> t(); - raise_typing_error "Malformed file. Source files must be encoded with UTF-8." {pfile = file; pmin = 0; pmax = 0} + raise_typing_error "Malformed file. Source files must be encoded with UTF-8." (file_pos file) | e -> t(); raise e diff --git a/tests/misc/projects/Issue8303/pretty-fail.hxml.stderr b/tests/misc/projects/Issue8303/pretty-fail.hxml.stderr index f3f273aa2cf..2cd268477fb 100644 --- a/tests/misc/projects/Issue8303/pretty-fail.hxml.stderr +++ b/tests/misc/projects/Issue8303/pretty-fail.hxml.stderr @@ -2,10 +2,8 @@ | Uncaught exception Stack overflow - -> Main.hx:1: character 1 + -> Main.hx - 1 | class Main { - | ^ | Called from here 8 | log(); From 68c95df3408925f56a58b4eb1097f47ed10c7831 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Tue, 23 Apr 2024 11:10:16 +0200 Subject: [PATCH 44/49] inherit `@:unreflective` on generic classes see https://github.com/HaxeFoundation/hxcpp/issues/1102 --- src/typing/generic.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typing/generic.ml b/src/typing/generic.ml index 6f12c785a94..efc992b41f0 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -312,7 +312,7 @@ let build_generic_class ctx c p tl = | Pure | Struct | StructInit | Using - | AutoBuild -> + | AutoBuild | Unreflective -> true | _ -> false From 0f4f6b569532835027f6d93f526837f35e14db19 Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Thu, 25 Apr 2024 09:10:44 +0200 Subject: [PATCH 45/49] [hl] add -D hl_w_null_compare (#11640) * [hl] add -D hl_w_null_compare * [hl] do not check eq, check null null --- src/generators/genhl.ml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index aa60213418f..b1421e20dcf 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -95,6 +95,7 @@ type context = { cfunctions : fundecl DynArray.t; cconstants : (constval, (global * int array)) lookup; optimize : bool; + w_null_compare : bool; overrides : (string * path, bool) Hashtbl.t; defined_funs : (int,unit) Hashtbl.t; is_macro : bool; @@ -1546,6 +1547,8 @@ and jump_expr ctx e jcond = | (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2) | HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2) -> + if ctx.w_null_compare && (is_nullt t1 || is_nullt t2) then + ctx.com.warning WGenerator [] (Printf.sprintf "Null compare: %s %s %s" (tstr t1) (s_binop jop) (tstr t2)) e.epos; let r1 = eval_expr ctx e1 in hold ctx r1; let jnull1 = if is_nullt t1 then jump ctx (fun i -> OJNull (r1, i)) else (fun i -> ()) in @@ -4113,6 +4116,7 @@ let create_context com is_macro dump = com = com; is_macro = is_macro; optimize = not (Common.raw_defined com "hl_no_opt"); + w_null_compare = Common.raw_defined com "hl_w_null_compare"; dump_out = if dump then Some (IO.output_channel (open_out_bin "dump/hlopt.txt")) else None; m = method_context 0 HVoid null_capture false; cints = new_lookup(); From 6e4fd96cb56b990cdf2b493733c326220489d500 Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Thu, 25 Apr 2024 10:46:11 +0200 Subject: [PATCH 46/49] Fix evalContext env leak, by Simn closes #11642 --- src/macro/eval/evalContext.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macro/eval/evalContext.ml b/src/macro/eval/evalContext.ml index 9249f6f3034..078fe59d930 100644 --- a/src/macro/eval/evalContext.ml +++ b/src/macro/eval/evalContext.ml @@ -467,7 +467,7 @@ let push_environment ctx info = env_locals = locals; env_captures = captures; env_extra_locals = IntMap.empty; - env_parent = eval.env; + env_parent = if info.kind = EKEntrypoint then None else eval.env; env_eval = eval; env_stack_depth = stack_depth; } in From 088afdce58534384116b650a6af99e21f7478e1e Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Fri, 26 Apr 2024 09:55:13 +0200 Subject: [PATCH 47/49] Add memory print that support details for macro interpreter (#11644) --- src/context/memory.ml | 71 +++++++++++++++++++++++++++++++++----- std/haxe/display/Server.hx | 8 ++++- 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/context/memory.ml b/src/context/memory.ml index c0613b9db62..6dd0f253d3c 100644 --- a/src/context/memory.ml +++ b/src/context/memory.ml @@ -113,6 +113,9 @@ let get_memory_json (cs : CompilationCache.t) mreq = "context",cc#get_json; "size",jint (mem_size cc); ]) contexts in + let mem_size_2 v exclude = + Objsize.size_with_headers (Objsize.objsize v exclude []) + in jobject [ "contexts",jarray j_contexts; "memory",jobject [ @@ -121,14 +124,66 @@ let get_memory_json (cs : CompilationCache.t) mreq = "haxelibCache",jint (mem_size cache_mem.(1)); "directoryCache",jint (mem_size cache_mem.(2)); "nativeLibCache",jint (mem_size cache_mem.(3)); - "additionalSizes",jarray [ - jobject ["name",jstring "macro interpreter";"size",jint (mem_size (MacroContext.macro_interp_cache))]; - (* jobject ["name",jstring "macro stdlib";"size",jint (mem_size (EvalContext.GlobalState.stdlib))]; - jobject ["name",jstring "macro macro_lib";"size",jint (mem_size (EvalContext.GlobalState.macro_lib))]; *) - jobject ["name",jstring "last completion result";"size",jint (mem_size (DisplayException.last_completion_result))]; - jobject ["name",jstring "Lexer file cache";"size",jint (mem_size (Lexer.all_files))]; - jobject ["name",jstring "GC heap words";"size",jint (int_of_float size)]; - ]; + "additionalSizes",jarray ( + (match !MacroContext.macro_interp_cache with + | Some interp -> + jobject ["name",jstring "macro interpreter";"size",jint (mem_size MacroContext.macro_interp_cache);"child",jarray [ + jobject ["name",jstring "builtins";"size",jint (mem_size_2 interp.builtins [Obj.repr interp])]; + jobject ["name",jstring "debug";"size",jint (mem_size_2 interp.debug [Obj.repr interp])]; + jobject ["name",jstring "curapi";"size",jint (mem_size_2 interp.curapi [Obj.repr interp])]; + jobject ["name",jstring "type_cache";"size",jint (mem_size_2 interp.type_cache [Obj.repr interp])]; + jobject ["name",jstring "overrides";"size",jint (mem_size_2 interp.overrides [Obj.repr interp])]; + jobject ["name",jstring "array_prototype";"size",jint (mem_size_2 interp.array_prototype [Obj.repr interp])]; + jobject ["name",jstring "string_prototype";"size",jint (mem_size_2 interp.string_prototype [Obj.repr interp])]; + jobject ["name",jstring "vector_prototype";"size",jint (mem_size_2 interp.vector_prototype [Obj.repr interp])]; + jobject ["name",jstring "instance_prototypes";"size",jint (mem_size_2 interp.instance_prototypes [Obj.repr interp])]; + jobject ["name",jstring "static_prototypes";"size",jint (mem_size_2 interp.static_prototypes [Obj.repr interp])]; + jobject ["name",jstring "constructors";"size",jint (mem_size_2 interp.constructors [Obj.repr interp])]; + jobject ["name",jstring "file_keys";"size",jint (mem_size_2 interp.file_keys [Obj.repr interp])]; + jobject ["name",jstring "toplevel";"size",jint (mem_size_2 interp.toplevel [Obj.repr interp])]; + jobject ["name",jstring "eval";"size",jint (mem_size_2 interp.eval [Obj.repr interp]);"child", jarray [ + (match interp.eval.env with + | Some env -> + jobject ["name",jstring "env";"size",jint (mem_size_2 interp.eval.env [Obj.repr interp; Obj.repr interp.eval]);"child", jarray [ + jobject ["name",jstring "env_info";"size",jint (mem_size_2 env.env_info [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])]; + jobject ["name",jstring "env_debug";"size",jint (mem_size_2 env.env_debug [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])]; + jobject ["name",jstring "env_locals";"size",jint (mem_size_2 env.env_locals [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])]; + jobject ["name",jstring "env_captures";"size",jint (mem_size_2 env.env_captures [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])]; + jobject ["name",jstring "env_extra_locals";"size",jint (mem_size_2 env.env_extra_locals [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])]; + jobject ["name",jstring "env_parent";"size",jint (mem_size_2 env.env_parent [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])]; + jobject ["name",jstring "env_eval";"size",jint (mem_size_2 env.env_eval [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])]; + ]]; + | None -> + jobject ["name",jstring "env";"size",jint (mem_size_2 interp.eval.env [Obj.repr interp; Obj.repr interp.eval])]; + ); + jobject ["name",jstring "thread";"size",jint (mem_size_2 interp.eval.thread [Obj.repr interp; Obj.repr interp.eval]);"child", jarray [ + jobject ["name",jstring "tthread";"size",jint (mem_size_2 interp.eval.thread.tthread [Obj.repr interp; Obj.repr interp.eval; Obj.repr interp.eval.thread])]; + jobject ["name",jstring "tdeque";"size",jint (mem_size_2 interp.eval.thread.tdeque [Obj.repr interp; Obj.repr interp.eval; Obj.repr interp.eval.thread])]; + jobject ["name",jstring "tevents";"size",jint (mem_size_2 interp.eval.thread.tevents [Obj.repr interp; Obj.repr interp.eval; Obj.repr interp.eval.thread])]; + jobject ["name",jstring "tstorage";"size",jint (mem_size_2 interp.eval.thread.tstorage [Obj.repr interp; Obj.repr interp.eval; Obj.repr interp.eval.thread])]; + ]]; + jobject ["name",jstring "debug_state";"size",jint (mem_size_2 interp.eval.debug_state [Obj.repr interp; Obj.repr interp.eval])]; + jobject ["name",jstring "breakpoint";"size",jint (mem_size_2 interp.eval.breakpoint [Obj.repr interp; Obj.repr interp.eval])]; + jobject ["name",jstring "caught_types";"size",jint (mem_size_2 interp.eval.caught_types [Obj.repr interp; Obj.repr interp.eval])]; + jobject ["name",jstring "caught_exception";"size",jint (mem_size_2 interp.eval.caught_exception [Obj.repr interp; Obj.repr interp.eval])]; + jobject ["name",jstring "last_return";"size",jint (mem_size_2 interp.eval.last_return [Obj.repr interp; Obj.repr interp.eval])]; + jobject ["name",jstring "debug_channel";"size",jint (mem_size_2 interp.eval.debug_channel [Obj.repr interp; Obj.repr interp.eval])]; + ]]; + jobject ["name",jstring "evals";"size",jint (mem_size_2 interp.evals [Obj.repr interp])]; + jobject ["name",jstring "exception_stack";"size",jint (mem_size_2 interp.exception_stack [Obj.repr interp])]; + ]]; + | None -> + jobject ["name",jstring "macro interpreter";"size",jint (mem_size MacroContext.macro_interp_cache)]; + ) + :: + [ + (* jobject ["name",jstring "macro stdlib";"size",jint (mem_size (EvalContext.GlobalState.stdlib))]; + jobject ["name",jstring "macro macro_lib";"size",jint (mem_size (EvalContext.GlobalState.macro_lib))]; *) + jobject ["name",jstring "last completion result";"size",jint (mem_size (DisplayException.last_completion_result))]; + jobject ["name",jstring "Lexer file cache";"size",jint (mem_size (Lexer.all_files))]; + jobject ["name",jstring "GC heap words";"size",jint (int_of_float size)]; + ] + ); ] ] | MContext sign -> diff --git a/std/haxe/display/Server.hx b/std/haxe/display/Server.hx index 0c20e60baf1..35a10e5ab93 100644 --- a/std/haxe/display/Server.hx +++ b/std/haxe/display/Server.hx @@ -111,6 +111,12 @@ typedef JsonServerFile = { final moduleName:Null; } +typedef AdditionalSize = { + final name:String; + final size:Int; + final child:Array; +} + /* Memory */ typedef HaxeMemoryResult = { final contexts:Array<{ @@ -123,7 +129,7 @@ typedef HaxeMemoryResult = { final haxelibCache:Int; final directoryCache:Int; final nativeLibCache:Int; - final ?additionalSizes:Array<{name:String, size:Int}>; + final ?additionalSizes:Array; } } From 547b510e177f68c4e2f9ca8861e06142a312c2ba Mon Sep 17 00:00:00 2001 From: Zeta <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Fri, 26 Apr 2024 12:15:41 +0200 Subject: [PATCH 48/49] [ci] Specify macOS runner versions instead of using macos-latest. (#11645) * [ci] Specify macOS runner versions instead of using macos-latest. Use `runner.arch` to decide where to upload the macOS artifacts. * [ci] Use macos-13 for tests. --- .github/workflows/main.yml | 8 ++++---- extra/github-actions/build-mac.yml | 4 ++-- extra/github-actions/workflows/main.yml | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 04b049d2ee9..1d9fa22a159 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -448,7 +448,7 @@ jobs: strategy: fail-fast: false matrix: - os: [macos-latest, macos-14] + os: [macos-14, macos-13] runs-on: ${{ matrix.os }} env: PLATFORM: mac @@ -543,14 +543,14 @@ jobs: otool -L ./haxelib - name: Upload artifact (x64) - if: matrix.os == 'macos-latest' + if: runner.arch == 'X64' uses: actions/upload-artifact@v4 with: name: macX64Binaries path: out - name: Upload artifact (arm) - if: matrix.os == 'macos-14' + if: runner.arch == 'ARM64' uses: actions/upload-artifact@v4 with: name: macArmBinaries @@ -689,7 +689,7 @@ jobs: mac-test: needs: mac-build-universal - runs-on: macos-latest + runs-on: macos-13 env: PLATFORM: mac TEST: ${{matrix.target}} diff --git a/extra/github-actions/build-mac.yml b/extra/github-actions/build-mac.yml index 543d9ba1105..65dcc41b4d8 100644 --- a/extra/github-actions/build-mac.yml +++ b/extra/github-actions/build-mac.yml @@ -56,14 +56,14 @@ otool -L ./haxelib - name: Upload artifact (x64) - if: matrix.os == 'macos-latest' + if: runner.arch == 'X64' uses: actions/upload-artifact@v4 with: name: macX64Binaries path: out - name: Upload artifact (arm) - if: matrix.os == 'macos-14' + if: runner.arch == 'ARM64' uses: actions/upload-artifact@v4 with: name: macArmBinaries diff --git a/extra/github-actions/workflows/main.yml b/extra/github-actions/workflows/main.yml index 1e360f97e8e..b7438c34015 100644 --- a/extra/github-actions/workflows/main.yml +++ b/extra/github-actions/workflows/main.yml @@ -308,7 +308,7 @@ jobs: strategy: fail-fast: false matrix: - os: [macos-latest, macos-14] + os: [macos-14, macos-13] runs-on: ${{ matrix.os }} env: PLATFORM: mac @@ -393,7 +393,7 @@ jobs: mac-test: needs: mac-build-universal - runs-on: macos-latest + runs-on: macos-13 env: PLATFORM: mac TEST: ${{matrix.target}} From c3258892c3c829ddd9faddcc0167108e62c84390 Mon Sep 17 00:00:00 2001 From: Zeta <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Fri, 26 Apr 2024 16:06:30 +0200 Subject: [PATCH 49/49] [mbedtls] Support mbedtls 3.x and fix bugs and compiler warnings. (#11646) * [mbedtls] Store bio functions in a GC root. * [mbedtls] Fix incorrect alt name check. * [mbedtls] Replace String_val with Bytes_val to prevent compiler warnings. * [mbedtls] use SecTrustCopyAnchorCertificates to get root certs on macOS. SecKeychainOpen is deprecated. * [mbedtls] Remove unused includes and use angled brackets. * [mbedtls] Fix more warnings. * [mbedtls] Support mbedtls 3.x. --- libs/mbedtls/mbedtls.ml | 4 +- libs/mbedtls/mbedtls_stubs.c | 103 ++++++++++++++--------------- src/macro/eval/evalSsl.ml | 8 +-- std/eval/_std/mbedtls/PkContext.hx | 4 +- std/eval/_std/sys/ssl/Key.hx | 4 +- 5 files changed, 61 insertions(+), 62 deletions(-) diff --git a/libs/mbedtls/mbedtls.ml b/libs/mbedtls/mbedtls.ml index dac738dde37..513cca45052 100644 --- a/libs/mbedtls/mbedtls.ml +++ b/libs/mbedtls/mbedtls.ml @@ -43,8 +43,8 @@ external mbedtls_ssl_setup : mbedtls_ssl_context -> mbedtls_ssl_config -> mbedtl external mbedtls_ssl_write : mbedtls_ssl_context -> bytes -> int -> int -> mbedtls_result = "ml_mbedtls_ssl_write" external mbedtls_pk_init : unit -> mbedtls_pk_context = "ml_mbedtls_pk_init" -external mbedtls_pk_parse_key : mbedtls_pk_context -> bytes -> string option -> mbedtls_result = "ml_mbedtls_pk_parse_key" -external mbedtls_pk_parse_keyfile : mbedtls_pk_context -> string -> string option -> mbedtls_result = "ml_mbedtls_pk_parse_keyfile" +external mbedtls_pk_parse_key : mbedtls_pk_context -> bytes -> string option -> mbedtls_ctr_drbg_context -> mbedtls_result = "ml_mbedtls_pk_parse_key" +external mbedtls_pk_parse_keyfile : mbedtls_pk_context -> string -> string option -> mbedtls_ctr_drbg_context -> mbedtls_result = "ml_mbedtls_pk_parse_keyfile" external mbedtls_pk_parse_public_keyfile : mbedtls_pk_context -> string -> mbedtls_result = "ml_mbedtls_pk_parse_public_keyfile" external mbedtls_pk_parse_public_key : mbedtls_pk_context -> bytes -> mbedtls_result = "ml_mbedtls_pk_parse_public_key" diff --git a/libs/mbedtls/mbedtls_stubs.c b/libs/mbedtls/mbedtls_stubs.c index f675e63213f..9d8132d9e07 100644 --- a/libs/mbedtls/mbedtls_stubs.c +++ b/libs/mbedtls/mbedtls_stubs.c @@ -1,4 +1,3 @@ -#include #include #include @@ -18,13 +17,10 @@ #include #include -#include "mbedtls/debug.h" #include "mbedtls/error.h" -#include "mbedtls/config.h" #include "mbedtls/ssl.h" #include "mbedtls/entropy.h" #include "mbedtls/ctr_drbg.h" -#include "mbedtls/certs.h" #include "mbedtls/oid.h" #define PVoid_val(v) (*((void**) Data_custom_val(v))) @@ -84,7 +80,7 @@ CAMLprim value ml_mbedtls_ctr_drbg_init(void) { CAMLprim value ml_mbedtls_ctr_drbg_random(value p_rng, value output, value output_len) { CAMLparam3(p_rng, output, output_len); - CAMLreturn(Val_int(mbedtls_ctr_drbg_random(CtrDrbg_val(p_rng), String_val(output), Int_val(output_len)))); + CAMLreturn(Val_int(mbedtls_ctr_drbg_random(CtrDrbg_val(p_rng), Bytes_val(output), Int_val(output_len)))); } CAMLprim value ml_mbedtls_ctr_drbg_seed(value ctx, value p_entropy, value custom) { @@ -124,7 +120,7 @@ CAMLprim value ml_mbedtls_entropy_init(void) { CAMLprim value ml_mbedtls_entropy_func(value data, value output, value len) { CAMLparam3(data, output, len); - CAMLreturn(Val_int(mbedtls_entropy_func(PVoid_val(data), String_val(output), Int_val(len)))); + CAMLreturn(Val_int(mbedtls_entropy_func(PVoid_val(data), Bytes_val(output), Int_val(len)))); } // Certificate @@ -171,7 +167,7 @@ CAMLprim value ml_mbedtls_x509_next(value chain) { CAMLprim value ml_mbedtls_x509_crt_parse(value chain, value bytes) { CAMLparam2(chain, bytes); - const char* buf = String_val(bytes); + const unsigned char* buf = Bytes_val(bytes); int len = caml_string_length(bytes); CAMLreturn(Val_int(mbedtls_x509_crt_parse(X509Crt_val(chain), buf, len + 1))); } @@ -191,8 +187,7 @@ CAMLprim value ml_mbedtls_x509_crt_parse_path(value chain, value path) { value caml_string_of_asn1_buf(mbedtls_asn1_buf* dat) { CAMLparam0(); CAMLlocal1(s); - s = caml_alloc_string(dat->len); - memcpy(String_val(s), dat->p, dat->len); + s = caml_alloc_initialized_string(dat->len, (const char *)dat->p); CAMLreturn(s); } @@ -200,7 +195,11 @@ CAMLprim value hx_cert_get_alt_names(value chain) { CAMLparam1(chain); CAMLlocal1(obj); mbedtls_x509_crt* cert = X509Crt_val(chain); - if (cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME == 0 || &cert->subject_alt_names == NULL) { +#if MBEDTLS_VERSION_MAJOR >= 3 + if (!mbedtls_x509_crt_has_ext_type(cert, MBEDTLS_X509_EXT_SUBJECT_ALT_NAME)) { +#else + if ((cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) == 0) { +#endif obj = Atom(0); } else { mbedtls_asn1_sequence* cur = &cert->subject_alt_names; @@ -366,29 +365,39 @@ CAMLprim value ml_mbedtls_pk_init(void) { CAMLreturn(obj); } -CAMLprim value ml_mbedtls_pk_parse_key(value ctx, value key, value password) { - CAMLparam3(ctx, key, password); - const char* pwd = NULL; +CAMLprim value ml_mbedtls_pk_parse_key(value ctx, value key, value password, value rng) { + CAMLparam4(ctx, key, password, rng); + const unsigned char* pwd = NULL; size_t pwdlen = 0; if (password != Val_none) { - pwd = String_val(Field(password, 0)); + pwd = Bytes_val(Field(password, 0)); pwdlen = caml_string_length(Field(password, 0)); } - CAMLreturn(mbedtls_pk_parse_key(PkContext_val(ctx), String_val(key), caml_string_length(key) + 1, pwd, pwdlen)); + #if MBEDTLS_VERSION_MAJOR >= 3 + mbedtls_ctr_drbg_context *ctr_drbg = CtrDrbg_val(rng); + CAMLreturn(mbedtls_pk_parse_key(PkContext_val(ctx), Bytes_val(key), caml_string_length(key) + 1, pwd, pwdlen, mbedtls_ctr_drbg_random, NULL)); + #else + CAMLreturn(mbedtls_pk_parse_key(PkContext_val(ctx), Bytes_val(key), caml_string_length(key) + 1, pwd, pwdlen)); + #endif } -CAMLprim value ml_mbedtls_pk_parse_keyfile(value ctx, value path, value password) { - CAMLparam3(ctx, path, password); +CAMLprim value ml_mbedtls_pk_parse_keyfile(value ctx, value path, value password, value rng) { + CAMLparam4(ctx, path, password, rng); const char* pwd = NULL; if (password != Val_none) { pwd = String_val(Field(password, 0)); } + #if MBEDTLS_VERSION_MAJOR >= 3 + mbedtls_ctr_drbg_context *ctr_drbg = CtrDrbg_val(rng); + CAMLreturn(mbedtls_pk_parse_keyfile(PkContext_val(ctx), String_val(path), pwd, mbedtls_ctr_drbg_random, ctr_drbg)); + #else CAMLreturn(mbedtls_pk_parse_keyfile(PkContext_val(ctx), String_val(path), pwd)); + #endif } CAMLprim value ml_mbedtls_pk_parse_public_key(value ctx, value key) { CAMLparam2(ctx, key); - CAMLreturn(mbedtls_pk_parse_public_key(PkContext_val(ctx), String_val(key), caml_string_length(key) + 1)); + CAMLreturn(mbedtls_pk_parse_public_key(PkContext_val(ctx), Bytes_val(key), caml_string_length(key) + 1)); } CAMLprim value ml_mbedtls_pk_parse_public_keyfile(value ctx, value path) { @@ -446,15 +455,14 @@ CAMLprim value ml_mbedtls_ssl_handshake(value ssl) { CAMLprim value ml_mbedtls_ssl_read(value ssl, value buf, value pos, value len) { CAMLparam4(ssl, buf, pos, len); - CAMLreturn(Val_int(mbedtls_ssl_read(SslContext_val(ssl), String_val(buf) + Int_val(pos), Int_val(len)))); + CAMLreturn(Val_int(mbedtls_ssl_read(SslContext_val(ssl), Bytes_val(buf) + Int_val(pos), Int_val(len)))); } static int bio_write_cb(void* ctx, const unsigned char* buf, size_t len) { CAMLparam0(); CAMLlocal3(r, s, vctx); - vctx = (value)ctx; - s = caml_alloc_string(len); - memcpy(String_val(s), buf, len); + vctx = *(value*)ctx; + s = caml_alloc_initialized_string(len, (const char*)buf); r = caml_callback2(Field(vctx, 1), Field(vctx, 0), s); CAMLreturn(Int_val(r)); } @@ -462,7 +470,7 @@ static int bio_write_cb(void* ctx, const unsigned char* buf, size_t len) { static int bio_read_cb(void* ctx, unsigned char* buf, size_t len) { CAMLparam0(); CAMLlocal3(r, s, vctx); - vctx = (value)ctx; + vctx = *(value*)ctx; s = caml_alloc_string(len); r = caml_callback2(Field(vctx, 2), Field(vctx, 0), s); memcpy(buf, String_val(s), len); @@ -476,7 +484,11 @@ CAMLprim value ml_mbedtls_ssl_set_bio(value ssl, value p_bio, value f_send, valu Store_field(ctx, 0, p_bio); Store_field(ctx, 1, f_send); Store_field(ctx, 2, f_recv); - mbedtls_ssl_set_bio(SslContext_val(ssl), (void*)ctx, bio_write_cb, bio_read_cb, NULL); + // TODO: this allocation is leaked + value *location = malloc(sizeof(value)); + *location = ctx; + caml_register_generational_global_root(location); + mbedtls_ssl_set_bio(SslContext_val(ssl), (void*)location, bio_write_cb, bio_read_cb, NULL); CAMLreturn(Val_unit); } @@ -492,7 +504,7 @@ CAMLprim value ml_mbedtls_ssl_setup(value ssl, value conf) { CAMLprim value ml_mbedtls_ssl_write(value ssl, value buf, value pos, value len) { CAMLparam4(ssl, buf, pos, len); - CAMLreturn(Val_int(mbedtls_ssl_write(SslContext_val(ssl), String_val(buf) + Int_val(pos), Int_val(len)))); + CAMLreturn(Val_int(mbedtls_ssl_write(SslContext_val(ssl), Bytes_val(buf) + Int_val(pos), Int_val(len)))); } // glue @@ -520,36 +532,23 @@ CAMLprim value hx_cert_load_defaults(value certificate) { #endif #ifdef __APPLE__ - CFMutableDictionaryRef search; - CFArrayRef result; - SecKeychainRef keychain; - SecCertificateRef item; - CFDataRef dat; - // Load keychain - if (SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain", &keychain) == errSecSuccess) { - // Search for certificates - search = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); - CFDictionarySetValue(search, kSecClass, kSecClassCertificate); - CFDictionarySetValue(search, kSecMatchLimit, kSecMatchLimitAll); - CFDictionarySetValue(search, kSecReturnRef, kCFBooleanTrue); - CFDictionarySetValue(search, kSecMatchSearchList, CFArrayCreate(NULL, (const void **)&keychain, 1, NULL)); - if (SecItemCopyMatching(search, (CFTypeRef *)&result) == errSecSuccess) { - CFIndex n = CFArrayGetCount(result); - for (CFIndex i = 0; i < n; i++) { - item = (SecCertificateRef)CFArrayGetValueAtIndex(result, i); - - // Get certificate in DER format - dat = SecCertificateCopyData(item); - if (dat) { - r = mbedtls_x509_crt_parse_der(chain, (unsigned char *)CFDataGetBytePtr(dat), CFDataGetLength(dat)); - CFRelease(dat); - if (r != 0) { - CAMLreturn(Val_int(r)); - } + CFArrayRef certs; + if (SecTrustCopyAnchorCertificates(&certs) == errSecSuccess) { + CFIndex count = CFArrayGetCount(certs); + for(CFIndex i = 0; i < count; i++) { + SecCertificateRef item = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i); + + // Get certificate in DER format + CFDataRef data = SecCertificateCopyData(item); + if(data) { + r = mbedtls_x509_crt_parse_der(chain, (unsigned char *)CFDataGetBytePtr(data), CFDataGetLength(data)); + CFRelease(data); + if (r != 0) { + CAMLreturn(Val_int(r)); } } } - CFRelease(keychain); + CFRelease(certs); } #endif diff --git a/src/macro/eval/evalSsl.ml b/src/macro/eval/evalSsl.ml index 3e22ec4dfd1..4da4b0355d0 100644 --- a/src/macro/eval/evalSsl.ml +++ b/src/macro/eval/evalSsl.ml @@ -160,11 +160,11 @@ let init_fields init_fields builtins = "strerror",vfun1 (fun code -> encode_string (mbedtls_strerror (decode_int code))); ] []; init_fields builtins (["mbedtls"],"PkContext") [] [ - "parse_key",vifun2 (fun this key password -> - vint (mbedtls_pk_parse_key (as_pk_context this) (decode_bytes key) (match password with VNull -> None | _ -> Some (decode_string password))); + "parse_key",vifun3 (fun this key password rng -> + vint (mbedtls_pk_parse_key (as_pk_context this) (decode_bytes key) (match password with VNull -> None | _ -> Some (decode_string password)) (as_ctr_drbg rng)); ); - "parse_keyfile",vifun2 (fun this path password -> - vint (mbedtls_pk_parse_keyfile (as_pk_context this) (decode_string path) (match password with VNull -> None | _ -> Some (decode_string password))); + "parse_keyfile",vifun3 (fun this path password rng -> + vint (mbedtls_pk_parse_keyfile (as_pk_context this) (decode_string path) (match password with VNull -> None | _ -> Some (decode_string password)) (as_ctr_drbg rng)); ); "parse_public_key",vifun1 (fun this key -> vint (mbedtls_pk_parse_public_key (as_pk_context this) (decode_bytes key)); diff --git a/std/eval/_std/mbedtls/PkContext.hx b/std/eval/_std/mbedtls/PkContext.hx index 0c83a4a47f4..6c0da6e935f 100644 --- a/std/eval/_std/mbedtls/PkContext.hx +++ b/std/eval/_std/mbedtls/PkContext.hx @@ -5,8 +5,8 @@ import haxe.io.Bytes; extern class PkContext { function new():Void; - function parse_key(key:Bytes, ?pwd:String):Int; - function parse_keyfile(path:String, ?password:String):Int; + function parse_key(key:Bytes, ?pwd:String, ctr_dbg: CtrDrbg):Int; + function parse_keyfile(path:String, ?password:String, ctr_dbg: CtrDrbg):Int; function parse_public_key(key:Bytes):Int; function parse_public_keyfile(path:String):Int; } diff --git a/std/eval/_std/sys/ssl/Key.hx b/std/eval/_std/sys/ssl/Key.hx index 67ea51a5cf8..b756a3dacf3 100644 --- a/std/eval/_std/sys/ssl/Key.hx +++ b/std/eval/_std/sys/ssl/Key.hx @@ -38,7 +38,7 @@ class Key { var code = if (isPublic) { key.native.parse_public_keyfile(file); } else { - key.native.parse_keyfile(file, pass); + key.native.parse_keyfile(file, pass, Mbedtls.getDefaultCtrDrbg()); } if (code != 0) { throw(mbedtls.Error.strerror(code)); @@ -51,7 +51,7 @@ class Key { var code = if (isPublic) { key.native.parse_public_key(data); } else { - key.native.parse_key(data); + key.native.parse_key(data, null, Mbedtls.getDefaultCtrDrbg()); } if (code != 0) { throw(mbedtls.Error.strerror(code));