diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8d2c2a39d55..e4941e8e0ac 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,7 +28,7 @@ jobs: with: timeout_minutes: 10 max_attempts: 10 - command: choco install --no-progress nsis.portable --version 3.02 -y + command: choco install --no-progress nsis.portable --version 3.09 -y - name: choco install things shell: pwsh @@ -143,7 +143,7 @@ jobs: with: timeout_minutes: 10 max_attempts: 10 - command: choco install --no-progress nsis.portable --version 3.02 -y + command: choco install --no-progress nsis.portable --version 3.09 -y - name: choco install things shell: pwsh @@ -259,6 +259,10 @@ jobs: env: PLATFORM: linux64 OPAMYES: 1 + strategy: + fail-fast: false + matrix: + ocaml: ["4.08.1", "5.0.0"] steps: - uses: actions/checkout@main with: @@ -269,7 +273,7 @@ jobs: uses: actions/cache@v3.0.11 with: path: ~/.opam/ - key: ${{ runner.os }}-${{ hashFiles('./haxe.opam', './libs/') }}-2 + key: ${{ runner.os }}-${{ matrix.ocaml }}-${{ hashFiles('./haxe.opam', './libs/') }} - name: Install Neko from S3 run: | @@ -303,6 +307,7 @@ jobs: set -ex opam init # --disable-sandboxing opam update + opam switch create ${{ matrix.ocaml }} opam pin add haxe . --no-action opam install haxe --deps-only --assume-depexts opam list @@ -330,6 +335,7 @@ jobs: run: echo "branch=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT - name: Build xmldoc + if: matrix.ocaml == '4.08.1' run: | set -ex make -s xmldoc @@ -343,11 +349,12 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v3 with: - name: linuxBinaries + name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }} path: out - name: Upload xmldoc artifact uses: actions/upload-artifact@v3 + if: matrix.ocaml == '4.08.1' with: name: xmldoc path: extra/doc @@ -363,6 +370,7 @@ jobs: strategy: fail-fast: false matrix: + ocaml: ["4.08.1", "5.0.0"] target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, lua, flash, neko] include: - target: hl @@ -379,7 +387,7 @@ jobs: submodules: recursive - uses: actions/download-artifact@v3 with: - name: linuxBinaries + name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }} path: linuxBinaries - name: Install Neko from S3 @@ -586,7 +594,7 @@ jobs: uses: actions/cache@v3.0.11 with: path: ~/.opam/ - key: ${{ runner.os }}-${{ hashFiles('./haxe.opam', './libs/') }}-2 + key: ${{ runner.os }}-${{ hashFiles('./haxe.opam', './libs/') }} - name: Install Neko from S3 run: | @@ -608,7 +616,7 @@ jobs: - name: Install dependencies env: # For compatibility with macOS 10.13 - ZLIB_VERSION: 1.2.13 + ZLIB_VERSION: 1.3 MBEDTLS_VERSION: 2.25.0 PCRE2_VERSION: 10.42 run: | diff --git a/Earthfile b/Earthfile index 8f399bb103a..dda473f6c60 100644 --- a/Earthfile +++ b/Earthfile @@ -93,6 +93,9 @@ devcontainer: # Install OCaml libraries COPY haxe.opam . RUN opam init --disable-sandboxing + RUN opam switch create 4.08.1 + RUN eval $(opam env) + RUN opam env RUN opam install . --yes --deps-only --no-depexts RUN opam list RUN ocamlopt -v diff --git a/extra/CHANGES.txt b/extra/CHANGES.txt index ce8d634a7f1..3eb4d6f20d0 100644 --- a/extra/CHANGES.txt +++ b/extra/CHANGES.txt @@ -1,3 +1,30 @@ +2023-09-01 4.3.2 + + General improvements: + + all : do not raise error on no-op reification outside macro + + Bugfixes: + + all : don't infer Null if it already is Null (#11286) + all : fix ?? inference and precedence (#11252) + all : bring back forced inline (#11217) + all : allow non constant "inline" var init with -D no-inline (#11192) + all : improve @:enum abstract deprecation warning handling (#11302) + all : fix some stack overflow with pretty errors + display : fix go to definition with final (#11173) + display : fix completion requests with @:forwardStatics (#11294) + eval : fix MainLoop.add not repeating (#11202) + hl/eval/neko : fix exception stack when wrapping native exceptions (#11249) + macro : map `this` when restoring typed expressions (#11212) + macro : safe navigation fix for ExprTools.map (#11204) + macro : safe navigation fix for haxe.macro.Printer (#11206) + macro : macro generated EVars position fixes (#11163) + macro : fix abstract casts for local statics (#11301) + macro : add flags to TDAbstract to be able to construct enum abstracts (#11230) + nullsafety : make break/continue expressions not-nullable (#11269) + nullsafety : handle return in assignment (#11114) + 2023-04-28 4.3.1 Breaking changes: diff --git a/extra/EnvVarUpdate.nsh b/extra/EnvVarUpdate.nsh index 39682000c35..5794a0d270c 100644 --- a/extra/EnvVarUpdate.nsh +++ b/extra/EnvVarUpdate.nsh @@ -43,7 +43,7 @@ !ifndef Un${StrFuncName}_INCLUDED ${Un${StrFuncName}} !endif - !define un.${StrFuncName} "${Un${StrFuncName}}" + !define un.${StrFuncName} '${Un${StrFuncName}}' !macroend !insertmacro _IncludeStrFunction StrTok diff --git a/extra/github-actions/build-mac.yml b/extra/github-actions/build-mac.yml index f4b838439da..f21797c360f 100644 --- a/extra/github-actions/build-mac.yml +++ b/extra/github-actions/build-mac.yml @@ -1,7 +1,7 @@ - name: Install dependencies env: # For compatibility with macOS 10.13 - ZLIB_VERSION: 1.2.13 + ZLIB_VERSION: 1.3 MBEDTLS_VERSION: 2.25.0 PCRE2_VERSION: 10.42 run: | diff --git a/extra/github-actions/cache-opam-windows.yml b/extra/github-actions/cache-opam-windows.yml deleted file mode 100644 index 5270fbf1fed..00000000000 --- a/extra/github-actions/cache-opam-windows.yml +++ /dev/null @@ -1,6 +0,0 @@ -- name: Cache opam - id: cache-opam - uses: actions/cache@v3.0.11 - with: - path: D:\.opam - key: ${{ runner.os }}${{ env.ARCH }}-${{ hashFiles('./haxe.opam', './libs/') }} diff --git a/extra/github-actions/cache-opam.yml b/extra/github-actions/cache-opam.yml deleted file mode 100644 index faaee00b723..00000000000 --- a/extra/github-actions/cache-opam.yml +++ /dev/null @@ -1,6 +0,0 @@ -- name: Cache opam - id: cache-opam - uses: actions/cache@v3.0.11 - with: - path: ~/.opam/ - key: ${{ runner.os }}-${{ hashFiles('./haxe.opam', './libs/') }}-2 diff --git a/extra/github-actions/install-nsis.yml b/extra/github-actions/install-nsis.yml index 752016d080e..5c77f1c978d 100644 --- a/extra/github-actions/install-nsis.yml +++ b/extra/github-actions/install-nsis.yml @@ -3,7 +3,7 @@ with: timeout_minutes: 10 max_attempts: 10 - command: choco install --no-progress nsis.portable --version 3.02 -y + command: choco install --no-progress nsis.portable --version 3.09 -y - name: choco install things shell: pwsh diff --git a/extra/github-actions/workflows/main.yml b/extra/github-actions/workflows/main.yml index 629d1bd640c..4b2825ccb37 100644 --- a/extra/github-actions/workflows/main.yml +++ b/extra/github-actions/workflows/main.yml @@ -57,12 +57,22 @@ jobs: env: PLATFORM: linux64 OPAMYES: 1 + strategy: + fail-fast: false + matrix: + ocaml: ["4.08.1", "5.0.0"] steps: - uses: actions/checkout@main with: submodules: recursive - @import cache-opam.yml + - name: Cache opam + id: cache-opam + uses: actions/cache@v3.0.11 + with: + path: ~/.opam/ + key: ${{ runner.os }}-${{ matrix.ocaml }}-${{ hashFiles('./haxe.opam', './libs/') }} + @import install-neko-unix.yml - name: Install dependencies @@ -79,6 +89,7 @@ jobs: set -ex opam init # --disable-sandboxing opam update + opam switch create ${{ matrix.ocaml }} opam pin add haxe . --no-action opam install haxe --deps-only --assume-depexts opam list @@ -106,6 +117,7 @@ jobs: run: echo "branch=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT - name: Build xmldoc + if: matrix.ocaml == '4.08.1' run: | set -ex make -s xmldoc @@ -119,11 +131,12 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v3 with: - name: linuxBinaries + name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }} path: out - name: Upload xmldoc artifact uses: actions/upload-artifact@v3 + if: matrix.ocaml == '4.08.1' with: name: xmldoc path: extra/doc @@ -139,6 +152,7 @@ jobs: strategy: fail-fast: false matrix: + ocaml: ["4.08.1", "5.0.0"] target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, lua, flash, neko] include: - target: hl @@ -155,7 +169,7 @@ jobs: submodules: recursive - uses: actions/download-artifact@v3 with: - name: linuxBinaries + name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }} path: linuxBinaries @import install-neko-unix.yml @@ -325,7 +339,13 @@ jobs: with: submodules: recursive - @import cache-opam.yml + - name: Cache opam + id: cache-opam + uses: actions/cache@v3.0.11 + with: + path: ~/.opam/ + key: ${{ runner.os }}-${{ hashFiles('./haxe.opam', './libs/') }} + @import install-neko-unix.yml @import build-mac.yml diff --git a/haxe.opam b/haxe.opam index 6a582f07288..9b3f38fe0c3 100644 --- a/haxe.opam +++ b/haxe.opam @@ -19,16 +19,18 @@ build: [ install: [make "install" "INSTALL_DIR=%{prefix}%"] remove: [make "uninstall" "INSTALL_DIR=%{prefix}%"] depends: [ - "ocaml" {>= "4.08"} + ("ocaml" {>= "5.0"} & ("camlp5" {build})) + | ("ocaml" {>= "4.08" & < "5.0"} & ("camlp5" {build & = "8.00"})) "ocamlfind" {build} "dune" {>= "1.11"} - "camlp5" {build & = "8.00"} "sedlex" {>= "2.0"} "xml-light" "extlib" {>= "1.7.8"} "sha" + "camlp-streams" "conf-libpcre2-8" "conf-zlib" "conf-neko" "luv" {>= "0.5.12"} + "ipaddr" ] diff --git a/libs/extc/extc_stubs.c b/libs/extc/extc_stubs.c index 30dc986d5c4..92faa58aa2a 100644 --- a/libs/extc/extc_stubs.c +++ b/libs/extc/extc_stubs.c @@ -92,7 +92,7 @@ int Zflush_val(value zflush_val) { case 4: return Z_FINISH; // TODO: support Z_BLOCK and Z_TREE // TODO: append the received value - default: failwith("Error in `Zflush_val` (extc_stubs.c): Unknown zflush value"); + default: caml_failwith("Error in `Zflush_val` (extc_stubs.c): Unknown zflush value"); } assert(0); } @@ -222,14 +222,14 @@ CAMLprim value zlib_deflate_init2(value level_val, value window_bits_val) { break; case Z_STREAM_ERROR: // TODO: use stream->msg to get _zlib_'s text message - failwith("Error in `zlib_deflate_init2` (extc_stubs.c): call to `deflateInit2` failed: Z_STREAM_ERROR"); + caml_failwith("Error in `zlib_deflate_init2` (extc_stubs.c): call to `deflateInit2` failed: Z_STREAM_ERROR"); break; case Z_VERSION_ERROR: // TODO: use stream->msg to get _zlib_'s text message - failwith("Error in `zlib_deflate_init2` (extc_stubs.c): call to `deflateInit2` failed: Z_VERSION_ERROR"); + caml_failwith("Error in `zlib_deflate_init2` (extc_stubs.c): call to `deflateInit2` failed: Z_VERSION_ERROR"); break; default: - failwith("Error in `zlib_deflate_init2` (extc_stubs.c): unknown return code from `deflateInit2`"); + caml_failwith("Error in `zlib_deflate_init2` (extc_stubs.c): unknown return code from `deflateInit2`"); } assert(0); } @@ -275,7 +275,7 @@ CAMLprim value zlib_deflate(value stream_val, value src, value spos, value slen, if (deflate_result == Z_OK || deflate_result == Z_STREAM_END) { stream->next_in = NULL; stream->next_out = NULL; - value zresult = alloc_small(3, 0); + value zresult = caml_alloc_small(3, 0); // z_finish Field(zresult, 0) = Val_bool(deflate_result == Z_STREAM_END); // z_read @@ -291,14 +291,14 @@ CAMLprim value zlib_deflate(value stream_val, value src, value spos, value slen, break; case Z_STREAM_ERROR: // TODO: use stream->msg to get _zlib_'s text message - failwith("Error in `zlib_deflate` (extc_stubs.c): call to `deflate` failed: Z_STREAM_ERROR"); + caml_failwith("Error in `zlib_deflate` (extc_stubs.c): call to `deflate` failed: Z_STREAM_ERROR"); break; case Z_BUF_ERROR: // TODO: use stream->msg to get _zlib_'s text message - failwith("Error in `zlib_deflate` (extc_stubs.c): call to `deflate` failed: Z_BUF_ERROR"); + caml_failwith("Error in `zlib_deflate` (extc_stubs.c): call to `deflate` failed: Z_BUF_ERROR"); break; default: - failwith("Error in `zlib_deflate` (extc_stubs.c): unknown return code from `deflate`"); + caml_failwith("Error in `zlib_deflate` (extc_stubs.c): unknown return code from `deflate`"); } assert(0); } @@ -309,14 +309,14 @@ CAMLprim value zlib_deflate_bytecode(value *arg, int nargs) { CAMLprim value zlib_deflate_end(value zv) { if( deflateEnd(ZStreamP_val(zv)) != 0 ) - failwith("zlib_deflate_end"); + caml_failwith("zlib_deflate_end"); return Val_unit; } CAMLprim value zlib_inflate_init(value wbits) { value z = zlib_new_stream(); if( inflateInit2(ZStreamP_val(z),Int_val(wbits)) != Z_OK ) - failwith("zlib_inflate_init"); + caml_failwith("zlib_inflate_init"); return z; } @@ -330,12 +330,12 @@ CAMLprim value zlib_inflate( value zv, value src, value spos, value slen, value z->avail_in = Int_val(slen); z->avail_out = Int_val(dlen); if( (r = inflate(z,Int_val(flush))) < 0 ) - failwith("zlib_inflate"); + caml_failwith("zlib_inflate"); z->next_in = NULL; z->next_out = NULL; - res = alloc_small(3, 0); + res = caml_alloc_small(3, 0); Field(res, 0) = Val_bool(r == Z_STREAM_END); Field(res, 1) = Val_int(Int_val(slen) - z->avail_in); Field(res, 2) = Val_int(Int_val(dlen) - z->avail_out); @@ -348,7 +348,7 @@ CAMLprim value zlib_inflate_bytecode(value * arg, int nargs) { CAMLprim value zlib_inflate_end(value zv) { if( inflateEnd(ZStreamP_val(zv)) != 0 ) - failwith("zlib_inflate_end"); + caml_failwith("zlib_inflate_end"); return Val_unit; } @@ -368,13 +368,13 @@ CAMLprim value executable_path(value u) { #ifdef _WIN32 char path[MAX_PATH]; if( GetModuleFileName(NULL,path,MAX_PATH) == 0 ) - failwith("executable_path"); + caml_failwith("executable_path"); return caml_copy_string(path); #elif __APPLE__ char path[MAXPATHLEN+1]; uint32_t path_len = MAXPATHLEN; if ( _NSGetExecutablePath(path, &path_len) ) - failwith("executable_path"); + caml_failwith("executable_path"); return caml_copy_string(path); #elif __FreeBSD__ char path[PATH_MAX]; @@ -387,7 +387,7 @@ CAMLprim value executable_path(value u) { len = sizeof(path); error = sysctl(name, 4, path, &len, NULL, 0); if( error < 0 ) - failwith("executable_path"); + caml_failwith("executable_path"); return caml_copy_string(path); #else char path[PATH_MAX]; @@ -397,7 +397,7 @@ CAMLprim value executable_path(value u) { if( p != NULL ) return caml_copy_string(p); else - failwith("executable_path"); + caml_failwith("executable_path"); } path[length] = '\0'; return caml_copy_string(path); @@ -408,12 +408,12 @@ CAMLprim value get_full_path( value f ) { #ifdef _WIN32 char path[MAX_PATH]; if( GetFullPathName(String_val(f),MAX_PATH,path,NULL) == 0 ) - failwith("get_full_path"); + caml_failwith("get_full_path"); return caml_copy_string(path); #else char path[4096]; if( realpath(String_val(f),path) == NULL ) - failwith("get_full_path"); + caml_failwith("get_full_path"); return caml_copy_string(path); #endif } @@ -428,7 +428,7 @@ CAMLprim value get_real_path( value path ) { // this will ensure the full class path with proper casing if( GetFullPathName(String_val(path),MAX_PATH,out,NULL) == 0 ) - failwith("get_real_path"); + caml_failwith("get_real_path"); len = strlen(out); i = 0; @@ -501,7 +501,7 @@ CAMLprim value sys_time() { ULARGE_INTEGER ui; GetSystemTime(&t); if( !SystemTimeToFileTime(&t,&ft) ) - failwith("sys_cpu_time"); + caml_failwith("sys_cpu_time"); ui.LowPart = ft.dwLowDateTime; ui.HighPart = ft.dwHighDateTime; return caml_copy_double( ((double)ui.QuadPart) / 10000000.0 - EPOCH_DIFF ); diff --git a/libs/extc/process_stubs.c b/libs/extc/process_stubs.c index c17c7a4f5bd..1f42c0fd1ad 100644 --- a/libs/extc/process_stubs.c +++ b/libs/extc/process_stubs.c @@ -67,10 +67,10 @@ #define val_null Val_int(0) #define val_some(v) Field(v,0) #define val_int(v) Int_val(v) -#define neko_error() failwith(__FUNCTION__) +#define neko_error() caml_failwith(__FUNCTION__) static value alloc_private( int size ) { - return alloc((size + sizeof(value) - 1) / sizeof(value), Abstract_tag); + return caml_alloc((size + sizeof(value) - 1) / sizeof(value), Abstract_tag); } // --- buffer api diff --git a/libs/extlib-leftovers/uTF8.ml b/libs/extlib-leftovers/uTF8.ml index ef61364deb0..ec25bd7aed9 100644 --- a/libs/extlib-leftovers/uTF8.ml +++ b/libs/extlib-leftovers/uTF8.ml @@ -177,7 +177,7 @@ let rec iter_aux proc s i = let iter proc s = iter_aux proc s 0 -let compare s1 s2 = Pervasives.compare s1 s2 +let compare s1 s2 = Stdlib.compare s1 s2 exception Malformed_code diff --git a/libs/ilib/peReader.ml b/libs/ilib/peReader.ml index fc79151e5b4..4d2e4aadb7a 100644 --- a/libs/ilib/peReader.ml +++ b/libs/ilib/peReader.ml @@ -25,7 +25,7 @@ open ExtList;; exception Error_message of string type reader_ctx = { - ch : Pervasives.in_channel; + ch : Stdlib.in_channel; i : IO.input; verbose : bool; } @@ -42,7 +42,7 @@ let seek r pos = seek_in r.ch pos let pos r = - Pervasives.pos_in r.ch + Stdlib.pos_in r.ch let info r msg = if r.verbose then diff --git a/libs/objsize/c_objsize.c b/libs/objsize/c_objsize.c index 5f222e0727c..4a316753177 100644 --- a/libs/objsize/c_objsize.c +++ b/libs/objsize/c_objsize.c @@ -12,6 +12,11 @@ #include "util.h" #include +#include + +#if OCAML_VERSION_MAJOR >= 5 +#include +#endif // FROM byterun/gc.h #define Caml_white (0 << 8) @@ -38,6 +43,7 @@ #define In_static_data 4 #define In_code_area 8 +#if OCAML_VERSION_MAJOR < 5 #ifdef ARCH_SIXTYFOUR // 64 bits: Represent page table as a sparse hash table @@ -63,6 +69,23 @@ CAMLextern unsigned char * caml_page_table[Pagetable1_size]; #define Is_in_heap_or_young(a) (Classify_addr(a) & (In_heap | In_young)) +void store_explicit(header_t hd, value v, int col) + { + Hd_val(v) = Coloredhd_hd(hd, col); + } + +#else + +void store_explicit(header_t hd, value v, int col) + { + atomic_store_explicit( + Hp_atomic_val(v), + Coloredhd_hd(hd, col), + memory_order_release); + } + +#endif + //-------------------------------------------------------- @@ -352,7 +375,7 @@ void c_rec_objsize(value v, size_t depth) DBG(printf("COL: w %08lx %i\n", v, col)); - Hd_val(v) = Coloredhd_hd(hd, Col_blue); + store_explicit(hd, v, Col_blue); if (Tag_val(v) < No_scan_tag) { @@ -378,7 +401,7 @@ void restore_colors(value v) col = readcolor(); DBG(printf("COL: r %08lx %i\n", v, col)); - Hd_val(v) = Coloredhd_hd(Hd_val(v), col); + store_explicit(Hd_val(v), v, col); if (Tag_val(v) < No_scan_tag) { @@ -417,7 +440,7 @@ int c_objsize(value v, value scan, value reach, size_t* headers, size_t* data, s head = Field(head,1); if( col == Col_blue ) continue; writecolor(col); - Hd_val(v) = Coloredhd_hd(hd, Col_blue); + store_explicit(hd, v, Col_blue); } acc_data = 0; @@ -444,7 +467,7 @@ int c_objsize(value v, value scan, value reach, size_t* headers, size_t* data, s head = Field(head,1); if( Colornum_hd(Hd_val(v)) != Col_blue ) continue; col = readcolor(); - Hd_val(v) = Coloredhd_hd(Hd_val(v), col); + store_explicit(Hd_val(v), v, col); } while( COND_BLOCK(reach) ) { diff --git a/libs/swflib/swfParser.ml b/libs/swflib/swfParser.ml index 2f647453261..8006c81ae52 100644 --- a/libs/swflib/swfParser.ml +++ b/libs/swflib/swfParser.ml @@ -444,7 +444,7 @@ and tag_length t = (* READ PRIMS *) let skip ch n = - seek_in ch ((Pervasives.pos_in ch) + n) + seek_in ch ((Stdlib.pos_in ch) + n) let read_rgba ch = let r = read_byte ch in diff --git a/libs/swflib/swfPic.ml b/libs/swflib/swfPic.ml index 7e69e28eb62..613260d189d 100644 --- a/libs/swflib/swfPic.ml +++ b/libs/swflib/swfPic.ml @@ -59,7 +59,7 @@ let load_picture file id = let len = String.length file in let p = (try String.rindex file '.' with Not_found -> len) in let ext = String.sub file (p + 1) (len - (p + 1)) in - match String.uppercase ext with + match ExtString.String.uppercase ext with | "PNG" -> let png , header, data = (try let p = Png.parse ch in diff --git a/libs/ttflib/tTFParser.ml b/libs/ttflib/tTFParser.ml index 68d1e26329a..9b3468ac7ee 100644 --- a/libs/ttflib/tTFParser.ml +++ b/libs/ttflib/tTFParser.ml @@ -24,7 +24,7 @@ open TTFData open IO type ctx = { - file : Pervasives.in_channel; + file : Stdlib.in_channel; ch : input; mutable entry : entry; } diff --git a/libs/ziplib/zip.ml b/libs/ziplib/zip.ml index 9245f0d00a2..0e5edc1eb52 100644 --- a/libs/ziplib/zip.ml +++ b/libs/ziplib/zip.ml @@ -62,7 +62,7 @@ type entry = type in_file = { if_filename: string; - if_channel: Pervasives.in_channel; + if_channel: Stdlib.in_channel; if_entries: entry list; if_directory: (string, entry) Hashtbl.t; if_comment: string } @@ -72,7 +72,7 @@ let comment ifile = ifile.if_comment type out_file = { of_filename: string; - of_channel: Pervasives.out_channel; + of_channel: Stdlib.out_channel; mutable of_entries: entry list; of_comment: string } @@ -217,7 +217,7 @@ let read_cd filename ic cd_entries cd_offset cd_bound = (* Open a ZIP file for reading *) let open_in filename = - let ic = Pervasives.open_in_bin filename in + let ic = Stdlib.open_in_bin filename in let (cd_entries, cd_size, cd_offset, cd_comment) = read_ecd filename ic in let entries = read_cd filename ic cd_entries cd_offset (Int32.add cd_offset cd_size) in @@ -232,7 +232,7 @@ let open_in filename = (* Close a ZIP file opened for reading *) let close_in ifile = - Pervasives.close_in ifile.if_channel + Stdlib.close_in ifile.if_channel (* Return the info associated with an entry *) @@ -369,7 +369,7 @@ let open_out ?(comment = "") filename = if String.length comment >= 0x10000 then raise(Error(filename, "", "comment too long")); { of_filename = filename; - of_channel = Pervasives.open_out_bin filename; + of_channel = Stdlib.open_out_bin filename; of_entries = []; of_comment = comment } @@ -416,7 +416,7 @@ let close_out ofile = write4_int oc start_cd; (* offset of central dir *) write2 oc (String.length ofile.of_comment); (* length of comment *) writestring oc ofile.of_comment; (* comment *) - Pervasives.close_out oc + Stdlib.close_out oc (* Write a local file header and return the corresponding entry *) @@ -552,9 +552,9 @@ let copy_file_to_entry infilename ofile ?(extra = "") ?(comment = "") with Unix.Unix_error(_,_,_) -> None in try copy_channel_to_entry ic ofile ~extra ~comment ~level ?mtime:mtime' name; - Pervasives.close_in ic + Stdlib.close_in ic with x -> - Pervasives.close_in ic; raise x + Stdlib.close_in ic; raise x (* Add an entry whose content will be produced by the caller *) diff --git a/src/codegen/codegen.ml b/src/codegen/codegen.ml index 84509ec8276..c4b211a1158 100644 --- a/src/codegen/codegen.ml +++ b/src/codegen/codegen.ml @@ -387,7 +387,8 @@ module Dump = struct let dep = Hashtbl.create 0 in List.iter (fun m -> print "%s:\n" (Path.UniqueKey.lazy_path m.m_extra.m_file); - PMap.iter (fun _ m2 -> + PMap.iter (fun _ (sign,mpath) -> + let m2 = (com.cs#get_context sign)#find_module mpath in let file = Path.UniqueKey.lazy_path m2.m_extra.m_file in print "\t%s\n" file; let l = try Hashtbl.find dep file with Not_found -> [] in diff --git a/src/codegen/dotnet.ml b/src/codegen/dotnet.ml index b0be29dec47..43fa7a58a8d 100644 --- a/src/codegen/dotnet.ml +++ b/src/codegen/dotnet.ml @@ -68,7 +68,7 @@ let cs_unops = let netname_to_hx name = let len = String.length name in let chr = String.get name 0 in - String.make 1 (Char.uppercase chr) ^ (String.sub name 1 (len-1)) + String.make 1 (Char.uppercase_ascii chr) ^ (String.sub name 1 (len-1)) (* -net-lib implementation *) @@ -105,7 +105,7 @@ let escape_chars = let netcl_to_hx cl = let cl = if String.length cl > 0 && String.get cl 0 >= 'a' && String.get cl 0 <= 'z' then - Char.escaped (Char.uppercase (String.get cl 0)) ^ (String.sub cl 1 (String.length cl - 1)) + Char.escaped (Char.uppercase_ascii (String.get cl 0)) ^ (String.sub cl 1 (String.length cl - 1)) else cl in diff --git a/src/codegen/java.ml b/src/codegen/java.ml index 5a6fcd9daa4..3a70f1d936f 100644 --- a/src/codegen/java.ml +++ b/src/codegen/java.ml @@ -46,7 +46,7 @@ let is_haxe_keyword = function let jname_to_hx name = let name = if name <> "" && (String.get name 0 < 'A' || String.get name 0 > 'Z') then - Char.escaped (Char.uppercase (String.get name 0)) ^ String.sub name 1 (String.length name - 1) + Char.escaped (Char.uppercase_ascii (String.get name 0)) ^ String.sub name 1 (String.length name - 1) else name in diff --git a/src/codegen/javaModern.ml b/src/codegen/javaModern.ml index 95c0fe3ffe1..8ccbd709e9d 100644 --- a/src/codegen/javaModern.ml +++ b/src/codegen/javaModern.ml @@ -555,7 +555,7 @@ module PathConverter = struct let jname_to_hx name = let name = if name <> "" && (String.get name 0 < 'A' || String.get name 0 > 'Z') then - Char.escaped (Char.uppercase (String.get name 0)) ^ String.sub name 1 (String.length name - 1) + Char.escaped (Char.uppercase_ascii (String.get name 0)) ^ String.sub name 1 (String.length name - 1) else name in diff --git a/src/codegen/swfLoader.ml b/src/codegen/swfLoader.ml index 18c324e83a9..2d2a25104f7 100644 --- a/src/codegen/swfLoader.ml +++ b/src/codegen/swfLoader.ml @@ -33,7 +33,7 @@ let lowercase_pack pack = let name = let fchar = String.get name 0 in if fchar >= 'A' && fchar <= 'Z' then - (String.make 1 (Char.lowercase fchar)) ^ String.sub name 1 (String.length name - 1) + (String.make 1 (Char.lowercase_ascii fchar)) ^ String.sub name 1 (String.length name - 1) else name in diff --git a/src/compiler/compilationContext.ml b/src/compiler/compilationContext.ml index 64e3f6b7f3e..0e18bce18d1 100644 --- a/src/compiler/compilationContext.ml +++ b/src/compiler/compilationContext.ml @@ -54,11 +54,11 @@ type server_api = { cache : CompilationCache.t; callbacks : compilation_callbacks; on_context_create : unit -> int; - init_wait_socket : string -> int -> server_accept; - init_wait_connect : string -> int -> server_accept; + init_wait_socket : (Ipaddr.V4.t, Ipaddr.V6.t) Ipaddr.v4v6 -> int -> server_accept; + init_wait_connect : (Ipaddr.V4.t, Ipaddr.V6.t) Ipaddr.v4v6 -> int -> server_accept; init_wait_stdio : unit -> server_accept; wait_loop : bool -> server_accept -> int; - do_connect : string -> int -> string list -> unit; + do_connect : (Ipaddr.V4.t, Ipaddr.V6.t) Ipaddr.v4v6 -> int -> string list -> unit; } let message ctx msg = diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index b2cd674ddc8..64c32ef30fb 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -143,7 +143,14 @@ module Setup = struct "python" | Hl -> add_std "hl"; - if not (Common.defined com Define.HlVer) then Define.define_value com.defines Define.HlVer (try Std.input_file (Common.find_file com "hl/hl_version") with Not_found -> die "" __LOC__); + if not (Common.defined com Define.HlVer) then begin + let hl_ver = try + Std.input_file (Common.find_file com "hl/hl_version") + with Not_found -> + failwith "The file hl_version could not be found. Please make sure HAXE_STD_PATH is set to the standard library corresponding to the used compiler version." + in + Define.define_value com.defines Define.HlVer hl_ver + end; "hl" | Eval -> add_std "eval"; @@ -565,8 +572,8 @@ module HighLevel = struct (* If we are already connected, ignore (issue #10813) *) loop acc l else begin - let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in - server_api.do_connect host (try int_of_string port with _ -> raise (Arg.Bad "Invalid port")) ((List.rev acc) @ l); + let host, port = Helper.parse_host_port hp in + server_api.do_connect host port ((List.rev acc) @ l); [],None end | "--server-connect" :: hp :: l -> diff --git a/src/compiler/displayProcessing.ml b/src/compiler/displayProcessing.ml index a55dfadd5be..ebdf508b9f0 100644 --- a/src/compiler/displayProcessing.ml +++ b/src/compiler/displayProcessing.ml @@ -269,7 +269,7 @@ let maybe_load_display_file_before_typing tctx display_file_dot_path = match dis let handle_display_after_typing ctx tctx display_file_dot_path = let com = ctx.com in - if ctx.com.display.dms_kind = DMNone & ctx.has_error then raise Abort; + if ctx.com.display.dms_kind = DMNone && ctx.has_error then raise Abort; begin match ctx.com.display.dms_kind,!Parser.delayed_syntax_completion with | DMDefault,Some(kind,subj) -> DisplayOutput.handle_syntax_completion com kind subj | _ -> () diff --git a/src/compiler/helper.ml b/src/compiler/helper.ml index 26e482ed1c3..2f99746cd17 100644 --- a/src/compiler/helper.ml +++ b/src/compiler/helper.ml @@ -1,3 +1,4 @@ +open Ipaddr exception HelpMessage of string let is_debug_run = try Sys.getenv "HAXEDEBUG" = "1" with _ -> false @@ -52,6 +53,16 @@ let parse_hxml file = parse_hxml_data data let parse_host_port hp = - let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in - let port = try int_of_string port with _ -> raise (Arg.Bad "Invalid port") in - host, port \ No newline at end of file + match (Ipaddr.with_port_of_string ~default:(-1) hp) with + (* Short ipv6 notation will be mixed up with port; extract port and rebuild ipv6 *) + | Ok (V6 ip, -1) -> + let octets = ExtLib.String.split_on_char ':' (V6.to_string ip) in + (match (List.rev octets) with + | port :: octets -> (try V6 (V6.of_string_exn (ExtLib.String.join ":" (List.rev octets))), int_of_string port with _ -> raise (Arg.Bad "Invalid host/port")) + | _ -> raise (Arg.Bad "Invalid host/port") + ) + | Ok (_, -1) -> raise (Arg.Bad "Invalid host/port: missing port") + | Ok (ip, port) -> ip, port + (* Default to 127.0.0.1 with given port if no host is provided *) + | Error _ when Str.string_match (Str.regexp "[0-9]+$") hp 0 -> V4 (V4.of_string_exn "127.0.0.1"), int_of_string hp + | Error _ -> raise (Arg.Bad "Invalid host/port") diff --git a/src/compiler/server.ml b/src/compiler/server.ml index 105bf636077..f3bcf3a6e0e 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -4,6 +4,7 @@ open CompilationCache open Timer open Type open DisplayProcessingGlobals +open Ipaddr open Json open CompilationContext open MessageReporting @@ -307,7 +308,9 @@ let check_module sctx ctx m p = end in let check_dependencies () = - PMap.iter (fun _ m2 -> match check m2 with + PMap.iter (fun _ (sign,mpath) -> + let m2 = (com.cs#get_context sign)#find_module mpath in + match check m2 with | None -> () | Some reason -> raise (Dirty (DependencyDirty(m2.m_path,reason))) ) m.m_extra.m_deps; @@ -407,7 +410,10 @@ let add_modules sctx ctx m p = ) m.m_types; TypeloadModule.ModuleLevel.add_module ctx m p; PMap.iter (Hashtbl.replace com.resources) m.m_extra.m_binded_res; - PMap.iter (fun _ m2 -> add_modules (tabs ^ " ") m0 m2) m.m_extra.m_deps + PMap.iter (fun _ (sign,mpath) -> + let m2 = (com.cs#get_context sign)#find_module mpath in + add_modules (tabs ^ " ") m0 m2 + ) m.m_extra.m_deps ) end in @@ -537,9 +543,16 @@ let init_wait_stdio() = mk_length_prefixed_communication false stdin stderr (* The connect function to connect to [host] at [port] and send arguments [args]. *) -let do_connect host port args = - let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in - (try Unix.connect sock (Unix.ADDR_INET (Unix.inet_addr_of_string host,port)) with _ -> failwith ("Couldn't connect on " ^ host ^ ":" ^ string_of_int port)); +let do_connect ip port args = + let (domain, host) = match ip with + | V4 ip -> (Unix.PF_INET, V4.to_string ip) + | V6 ip -> (Unix.PF_INET6, V6.to_string ip) + in + let sock = Unix.socket domain Unix.SOCK_STREAM 0 in + (try Unix.connect sock (Unix.ADDR_INET (Unix.inet_addr_of_string host,port)) with + | Unix.Unix_error(code,_,_) -> failwith("Couldn't connect on " ^ host ^ ":" ^ string_of_int port ^ " (" ^ (Unix.error_message code) ^ ")"); + | _ -> failwith ("Couldn't connect on " ^ host ^ ":" ^ string_of_int port) + ); let rec display_stdin args = match args with | [] -> "" @@ -702,14 +715,22 @@ and wait_loop verbose accept = 0 (* Connect to given host/port and return accept function for communication *) -and init_wait_connect host port = +and init_wait_connect ip port = + let host = match ip with + | V4 ip -> V4.to_string ip + | V6 ip -> V6.to_string ip + in let host = Unix.inet_addr_of_string host in let chin, chout = Unix.open_connection (Unix.ADDR_INET (host,port)) in mk_length_prefixed_communication true chin chout (* The accept-function to wait for a socket connection. *) -and init_wait_socket host port = - let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in +and init_wait_socket ip port = + let (domain, host) = match ip with + | V4 ip -> (Unix.PF_INET, V4.to_string ip) + | V6 ip -> (Unix.PF_INET6, V6.to_string ip) + in + let sock = Unix.socket domain Unix.SOCK_STREAM 0 in (try Unix.setsockopt sock Unix.SO_REUSEADDR true with _ -> ()); (try Unix.bind sock (Unix.ADDR_INET (Unix.inet_addr_of_string host,port)) with _ -> failwith ("Couldn't wait on " ^ host ^ ":" ^ string_of_int port)); ServerMessage.socket_message ("Waiting on " ^ host ^ ":" ^ string_of_int port); diff --git a/src/context/display/displayException.ml b/src/context/display/displayException.ml index a731f9a1d98..661bb1bd17b 100644 --- a/src/context/display/displayException.ml +++ b/src/context/display/displayException.ml @@ -23,9 +23,9 @@ let max_completion_items = ref 0 let filter_somehow ctx items kind subj = let subject = match subj.s_name with | None -> "" - | Some name-> String.lowercase name + | Some name-> ExtString.String.lowercase name in - let subject_length = String.length subject in + let subject_length = ExtString.String.length subject in let determine_cost s = let get_initial_cost o = if o = 0 then @@ -33,7 +33,7 @@ let filter_somehow ctx items kind subj = else begin (* Consider `.` as anchors and determine distance from closest one. Penalize starting distance by factor 2. *) try - let last_anchor = String.rindex_from s o '.' in + let last_anchor = ExtString.String.rindex_from s o '.' in (o - (last_anchor + 1)) * 2 with Not_found -> o * 2 @@ -54,12 +54,12 @@ let filter_somehow ctx items kind subj = let o',new_cost = index_from o subject.[i] in loop (i + 1) o' (cost + new_cost) end else - cost + (if o = String.length s - 1 then 0 else 1) (* Slightly penalize for not-exact matches. *) + cost + (if o = ExtString.String.length s - 1 then 0 else 1) (* Slightly penalize for not-exact matches. *) in if subject_length = 0 then 0 else try - let o = String.index s subject.[0] in + let o = ExtString.String.index s subject.[0] in loop 1 o (get_initial_cost o); with Not_found | Invalid_argument _ -> -1 @@ -67,7 +67,7 @@ let filter_somehow ctx items kind subj = let rec loop acc items index = match items with | item :: items -> - let name = String.lowercase (get_filter_name item) in + let name = ExtString.String.lowercase (get_filter_name item) in let cost = determine_cost name in let acc = if cost >= 0 then (item,index,cost) :: acc @@ -102,8 +102,8 @@ let patch_completion_subject subj = match subj.s_name with | Some name -> let delta = p.pmax - p.pmin in - let name = if delta > 0 && delta < String.length name then - String.sub name 0 delta + let name = if delta > 0 && delta < ExtString.String.length name then + ExtString.String.sub name 0 delta else name in diff --git a/src/context/display/displayFields.ml b/src/context/display/displayFields.ml index fb587833e4c..346a9368c64 100644 --- a/src/context/display/displayFields.ml +++ b/src/context/display/displayFields.ml @@ -228,21 +228,25 @@ let collect ctx e_ast e dk with_type p = | TAnon an -> (* @:forwardStatics *) let items = match !(an.a_status) with - | Statics { cl_kind = KAbstractImpl { a_meta = meta; a_this = TInst (c,_) }} when Meta.has Meta.ForwardStatics meta -> - let items = List.fold_left (fun acc cf -> - if should_access c cf true && is_new_item acc cf.cf_name then begin - let origin = Self(TClassDecl c) in - let item = make_class_field origin cf in - PMap.add cf.cf_name item acc - end else - acc - ) items c.cl_ordered_statics in - PMap.foldi (fun name item acc -> - if is_new_item acc name then - PMap.add name item acc - else - acc - ) PMap.empty items + | Statics { cl_kind = KAbstractImpl { a_meta = meta; a_this}} when Meta.has Meta.ForwardStatics meta -> + begin match follow a_this with + | TInst (c,_) -> + let items = List.fold_left (fun acc cf -> + if should_access c cf true && is_new_item acc cf.cf_name then begin + let origin = Self(TClassDecl c) in + let item = make_class_field origin cf in + PMap.add cf.cf_name item acc + end else + acc + ) items c.cl_ordered_statics in + PMap.foldi (fun name item acc -> + if is_new_item acc name then + PMap.add name item acc + else + acc + ) PMap.empty items + | _ -> items + end | _ -> items in (* Anon own fields *) diff --git a/src/context/display/displayJson.ml b/src/context/display/displayJson.ml index 06a336c8aac..1ed9e25cd25 100644 --- a/src/context/display/displayJson.ml +++ b/src/context/display/displayJson.ml @@ -182,13 +182,14 @@ let handler = "server/module", (fun hctx -> let sign = Digest.from_hex (hctx.jsonrpc#get_string_param "signature") in let path = Path.parse_path (hctx.jsonrpc#get_string_param "path") in - let cc = hctx.display#get_cs#get_context sign in + let cs = hctx.display#get_cs in + let cc = cs#get_context sign in let m = try cc#find_module path with Not_found -> hctx.send_error [jstring "No such module"] in - hctx.send_result (generate_module cc m) + hctx.send_result (generate_module cs cc m) ); "server/type", (fun hctx -> let sign = Digest.from_hex (hctx.jsonrpc#get_string_param "signature") in diff --git a/src/context/display/documentSymbols.ml b/src/context/display/documentSymbols.ml index 705c8be1dee..4d61a6ae4ef 100644 --- a/src/context/display/documentSymbols.ml +++ b/src/context/display/documentSymbols.ml @@ -56,7 +56,7 @@ let collect_module_symbols mname with_locals (pack,decls) = | FFun f -> add_field ( if fst cff_name = "new" then Constructor - else if ((parent_kind = EnumAbstract or parent_kind = Abstract) && Meta.has_one_of [Meta.Op; Meta.ArrayAccess; Meta.Resolve] cff_meta) then Operator + else if ((parent_kind = EnumAbstract || parent_kind = Abstract) && Meta.has_one_of [Meta.Op; Meta.ArrayAccess; Meta.Resolve] cff_meta) then Operator else Method ); if with_locals then func field_parent f diff --git a/src/context/memory.ml b/src/context/memory.ml index 9b692d344d9..8d16ca17ffe 100644 --- a/src/context/memory.ml +++ b/src/context/memory.ml @@ -33,12 +33,14 @@ let update_module_type_deps deps md = ) md.m_types; !deps -let rec scan_module_deps m h = +let rec scan_module_deps cs m h = if Hashtbl.mem h m.m_id then () else begin Hashtbl.add h m.m_id m; - PMap.iter (fun _ m -> scan_module_deps m h) m.m_extra.m_deps + PMap.iter (fun _ (sign,mpath) -> + let m = (cs#get_context sign)#find_module mpath in + scan_module_deps cs m h) m.m_extra.m_deps end let module_sign key md = @@ -61,7 +63,7 @@ let get_out out = let get_module_memory cs all_modules m = let mdeps = Hashtbl.create 0 in - scan_module_deps m mdeps; + scan_module_deps cs m mdeps; let deps = ref [Obj.repr null_module] in let out = ref all_modules in let deps = Hashtbl.fold (fun _ md deps -> @@ -272,8 +274,9 @@ let display_memory com = ()); if verbose then begin print (Printf.sprintf " %d total deps" (List.length deps)); - PMap.iter (fun _ md -> - print (Printf.sprintf " dep %s%s" (s_type_path md.m_path) (module_sign key md)); + PMap.iter (fun _ (sign,mpath) -> + let md = (com.cs#get_context sign)#find_module mpath in + print (Printf.sprintf " dep %s%s" (s_type_path mpath) (module_sign key md)); ) m.m_extra.m_deps; end; flush stdout diff --git a/src/context/typecore.ml b/src/context/typecore.ml index 6b60b8d6676..5c5457e207c 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -629,7 +629,7 @@ let merge_core_doc ctx mt = let field_to_type_path com e = let rec loop e pack name = match e with - | EField(e,f,_),p when Char.lowercase (String.get f 0) <> String.get f 0 -> (match name with + | EField(e,f,_),p when Char.lowercase_ascii (String.get f 0) <> String.get f 0 -> (match name with | [] | _ :: [] -> loop e pack (f :: name) | _ -> (* too many name paths *) @@ -641,7 +641,7 @@ let field_to_type_path com e = let pack, name, sub = match name with | [] -> let fchar = String.get f 0 in - if Char.uppercase fchar = fchar then + if Char.uppercase_ascii fchar = fchar then pack, f, None else begin display_error com "A class name must start with an uppercase letter" (snd e); @@ -691,12 +691,12 @@ let s_field_call_candidate fcc = let relative_path ctx file = let slashes path = String.concat "/" (ExtString.String.nsplit path "\\") in let fpath = slashes (Path.get_full_path file) in - let fpath_lower = String.lowercase fpath in + let fpath_lower = String.lowercase_ascii fpath in let flen = String.length fpath_lower in let rec loop = function | [] -> file | path :: l -> - let spath = String.lowercase (slashes path) in + let spath = String.lowercase_ascii (slashes path) in let slen = String.length spath in if slen > 0 && slen < flen && String.sub fpath_lower 0 slen = spath then String.sub fpath slen (flen - slen) else loop l in @@ -740,14 +740,13 @@ let get_next_stored_typed_expr_id = let uid = ref 0 in (fun() -> incr uid; !uid) -let get_stored_typed_expr com id = - let e = com.stored_typed_exprs#find id in - Texpr.duplicate_tvars e +let make_stored_id_expr id p = + (EConst (Int (string_of_int id, None))), p let store_typed_expr com te p = let id = get_next_stored_typed_expr_id() in com.stored_typed_exprs#add id te; - let eid = (EConst (Int (string_of_int id, None))), p in + let eid = make_stored_id_expr id p in id,((EMeta ((Meta.StoredTypedExpr,[],null_pos), eid)),p) let push_this ctx e = match e.eexpr with diff --git a/src/core/json/genjson.ml b/src/core/json/genjson.ml index ed85b04a7a1..c3f79615fdf 100644 --- a/src/core/json/genjson.ml +++ b/src/core/json/genjson.ml @@ -707,7 +707,7 @@ let generate_module_type ctx mt = (* module *) -let generate_module cc m = +let generate_module cs cc m = jobject [ "id",jint m.m_id; "path",generate_module_path m.m_path; @@ -718,10 +718,12 @@ let generate_module cc m = | MSGood -> "Good" | MSBad reason -> Printer.s_module_skip_reason reason | MSUnknown -> "Unknown"); - "dependencies",jarray (PMap.fold (fun m acc -> (jobject [ - "path",jstring (s_type_path m.m_path); - "sign",jstring (Digest.to_hex m.m_extra.m_sign); - ]) :: acc) m.m_extra.m_deps []); + "dependencies",jarray (PMap.fold (fun (sign,mpath) acc -> + (jobject [ + "path",jstring (s_type_path mpath); + "sign",jstring (Digest.to_hex ((cs#get_context sign)#find_module mpath).m_extra.m_sign); + ]) :: acc + ) m.m_extra.m_deps []); "dependents",jarray (List.map (fun m -> (jobject [ "path",jstring (s_type_path m.m_path); "sign",jstring (Digest.to_hex m.m_extra.m_sign); diff --git a/src/core/path.ml b/src/core/path.ml index c5bf6d74d08..119908524b8 100644 --- a/src/core/path.ml +++ b/src/core/path.ml @@ -223,7 +223,7 @@ end = struct let create = if Globals.is_windows then - (fun f -> String.lowercase (get_full_path f)) + (fun f -> ExtString.String.lowercase (get_full_path f)) else get_full_path @@ -378,7 +378,7 @@ let full_dot_path pack mname tname = let file_extension file = match List.rev (ExtString.String.nsplit file ".") with - | e :: _ -> String.lowercase e + | e :: _ -> ExtString.String.lowercase e | [] -> "" module FilePath = struct diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index ca65239513d..5e46556b617 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -233,8 +233,8 @@ let null_abstract = { } let add_dependency ?(skip_postprocess=false) m mdep = - if m != null_module && m != mdep then begin - m.m_extra.m_deps <- PMap.add mdep.m_id mdep m.m_extra.m_deps; + if m != null_module && (m.m_path != mdep.m_path || m.m_extra.m_sign != mdep.m_extra.m_sign) then begin + m.m_extra.m_deps <- PMap.add mdep.m_id (mdep.m_extra.m_sign, mdep.m_path) m.m_extra.m_deps; (* In case the module is cached, we'll have to run post-processing on it again (issue #10635) *) if not skip_postprocess then m.m_extra.m_processed <- 0 end diff --git a/src/core/tPrinting.ml b/src/core/tPrinting.ml index c386969efde..a54815532be 100644 --- a/src/core/tPrinting.ml +++ b/src/core/tPrinting.ml @@ -605,7 +605,7 @@ module Printer = struct "m_cache_state",s_module_cache_state me.m_cache_state; "m_added",string_of_int me.m_added; "m_checked",string_of_int me.m_checked; - "m_deps",s_pmap string_of_int (fun m -> snd m.m_path) me.m_deps; + "m_deps",s_pmap string_of_int (fun (_,m) -> snd m) me.m_deps; "m_processed",string_of_int me.m_processed; "m_kind",s_module_kind me.m_kind; "m_binded_res",""; (* TODO *) diff --git a/src/core/tType.ml b/src/core/tType.ml index dd328432ebb..6ec5f025b21 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -390,7 +390,7 @@ and module_def_extra = { mutable m_added : int; mutable m_checked : int; mutable m_processed : int; - mutable m_deps : (int,module_def) PMap.t; + mutable m_deps : (int,(string (* sign *) * path)) PMap.t; mutable m_kind : module_kind; mutable m_binded_res : (string, string) PMap.t; mutable m_if_feature : (string *(tclass * tclass_field * bool)) list; diff --git a/src/core/texpr.ml b/src/core/texpr.ml index 540ede76f6c..43f9aad0657 100644 --- a/src/core/texpr.ml +++ b/src/core/texpr.ml @@ -232,7 +232,7 @@ let map_expr_type f ft fv e = | TFunction fu -> let fu = { tf_expr = f fu.tf_expr; - tf_args = List.map (fun (v,o) -> fv v, o) fu.tf_args; + tf_args = List.map (fun (v,o) -> fv v, (Option.map f o)) fu.tf_args; tf_type = ft fu.tf_type; } in { e with eexpr = TFunction fu; etype = ft e.etype } @@ -307,7 +307,9 @@ let rec equal e1 e2 = match e1.eexpr,e2.eexpr with | TEnumParameter(e1,ef1,i1),TEnumParameter(e2,ef2,i2) -> equal e1 e2 && ef1 == ef2 && i1 = i2 | _ -> false -let duplicate_tvars e = +let e_identity e = e + +let duplicate_tvars f_this e = let vars = Hashtbl.create 0 in let copy_var v = let v2 = alloc_var v.v_kind v.v_name v.v_type v.v_pos in @@ -344,6 +346,8 @@ let duplicate_tvars e = {e with eexpr = TLocal v2} with _ -> e) + | TConst TThis -> + f_this e | _ -> map_expr build_expr e in diff --git a/src/dune b/src/dune index 045db889643..63d49be3ba2 100644 --- a/src/dune +++ b/src/dune @@ -17,9 +17,9 @@ (library (name haxe) (libraries - extc extproc extlib_leftovers ilib javalib mbedtls neko objsize pcre2 swflib ttflib ziplib + extc extproc extlib_leftovers ilib javalib mbedtls neko objsize pcre2 camlp-streams swflib ttflib ziplib json - unix str bigarray threads dynlink + unix ipaddr str bigarray threads dynlink xml-light extlib sha luv ) diff --git a/src/filters/filters.ml b/src/filters/filters.ml index 866a4d4c6b1..72ff6e8774a 100644 --- a/src/filters/filters.ml +++ b/src/filters/filters.ml @@ -75,6 +75,7 @@ module LocalStatic = struct raise_typing_error ~depth:1 "Conflicting field was found here" cf.cf_name_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; begin match eo with | None -> () diff --git a/src/generators/gencpp.ml b/src/generators/gencpp.ml index e417bbbb718..edd687642d7 100644 --- a/src/generators/gencpp.ml +++ b/src/generators/gencpp.ml @@ -7035,8 +7035,8 @@ let write_build_options common_ctx filename defines = | _ -> write_define name (escape_command value)) defines; let pin,pid = Process_helper.open_process_args_in_pid "haxelib" [|"haxelib"; "path"; "hxcpp"|] in set_binary_mode_in pin false; - write_define "hxcpp" (Pervasives.input_line pin); - Pervasives.ignore (Process_helper.close_process_in_pid (pin,pid)); + write_define "hxcpp" (Stdlib.input_line pin); + Stdlib.ignore (Process_helper.close_process_in_pid (pin,pid)); writer#close;; let create_member_types common_ctx = diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index 7db70613ea8..14b6618ee41 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -130,6 +130,7 @@ type access = | AInstanceProto of texpr * field index | AInstanceField of texpr * field index | AArray of reg * (ttype * ttype) * reg + | ACArray of reg * ttype * reg | AVirtualMethod of texpr * field index | ADynamic of texpr * string index | AEnum of tenum * field index @@ -309,6 +310,12 @@ let unsigned_op e1 e2 = in is_unsigned e1 && is_unsigned e2 +let rec get_const e = + match e.eexpr with + | TConst c -> c + | TParenthesis e | TCast (e,_) -> get_const e + | _ -> abort "Should be a constant" e.epos + let set_curpos ctx p = ctx.m.mcurpos <- p @@ -1376,6 +1383,13 @@ and get_access ctx e = free ctx a; let t = to_type ctx t in AArray (a,(t,t),i) + | TInst ({ cl_path = ["hl"],"Abstract" },[TInst({ cl_kind = KExpr (EConst (String("hl_carray",_)),_) },_)]) -> + let a = eval_null_check ctx a in + hold ctx a; + let i = eval_to ctx i HI32 in + free ctx a; + let t = to_type ctx e.etype in + ACArray (a,t,i) | TAbstract (a,pl) -> loop (Abstract.get_underlying_type a pl) | _ -> @@ -1893,7 +1907,13 @@ and eval_expr ctx e = r | "$asize", [e] -> let r = alloc_tmp ctx HI32 in - op ctx (OArraySize (r, eval_to ctx e HArray)); + (match follow e.etype with + | TInst ({cl_path=["hl"],"Abstract"},[TInst({ cl_kind = KExpr (EConst (String("hl_carray",_)),_) },_)]) -> + let arr = eval_expr ctx e in + op ctx (ONullCheck arr); + op ctx (OArraySize (r, arr)) + | _ -> + op ctx (OArraySize (r, eval_to ctx e HArray))); r | "$aalloc", [esize] -> let et = (match follow e.etype with TAbstract ({ a_path = ["hl"],"NativeArray" },[t]) -> to_type ctx t | _ -> invalid()) in @@ -2053,6 +2073,15 @@ and eval_expr ctx e = free ctx rfile; free ctx min; r + | "$prefetch", [value; mode] -> + let mode = (match get_const mode with + | TInt m -> Int32.to_int m + | _ -> abort "Constant mode required" e.epos + ) in + (match get_access ctx value with + | AInstanceField (f, index) -> op ctx (OPrefetch (eval_expr ctx f, index + 1, mode)) + | _ -> op ctx (OPrefetch (eval_expr ctx value, 0, mode))); + alloc_tmp ctx HVoid | _ -> abort ("Unknown native call " ^ s) e.epos) | TEnumIndex v -> @@ -2207,7 +2236,7 @@ and eval_expr ctx e = ignore(make_fun ctx ("","") fid f None None); end; op ctx (OStaticClosure (r,fid)); - | ANone | ALocal _ | AArray _ | ACaptured _ -> + | ANone | ALocal _ | AArray _ | ACaptured _ | ACArray _ -> abort "Invalid access" e.epos); let to_t = to_type ctx e.etype in (match to_t with @@ -2451,7 +2480,7 @@ and eval_expr ctx e = let r = value() in op ctx (OSetEnumField (ctx.m.mcaptreg,index,r)); r - | AEnum _ | ANone | AInstanceFun _ | AInstanceProto _ | AStaticFun _ | AVirtualMethod _ -> + | AEnum _ | ANone | AInstanceFun _ | AInstanceProto _ | AStaticFun _ | AVirtualMethod _ | ACArray _ -> die "" __LOC__) | OpBoolOr -> let r = alloc_tmp ctx HBool in @@ -2726,6 +2755,10 @@ and eval_expr ctx e = (match get_access ctx e with | AArray (a,at,idx) -> array_read ctx a at idx e.epos + | ACArray (a,t,idx) -> + let tmp = alloc_tmp ctx t in + op ctx (OGetArray (tmp,a,idx)); + tmp | _ -> die "" __LOC__) | TMeta (_,e) -> @@ -3045,7 +3078,7 @@ and gen_assign_op ctx acc e1 f = free ctx robj; op ctx (ODynSet (robj,fid,r)); r - | ANone | ALocal _ | AStaticFun _ | AInstanceFun _ | AInstanceProto _ | AVirtualMethod _ | AEnum _ -> + | ANone | ALocal _ | AStaticFun _ | AInstanceFun _ | AInstanceProto _ | AVirtualMethod _ | AEnum _ | ACArray _ -> die "" __LOC__ and build_capture_vars ctx f = @@ -4063,7 +4096,7 @@ let add_types ctx types = | Method MethNormal when not (List.exists (fun (m,_,_) -> m = Meta.HlNative) f.cf_meta) -> (match f.cf_expr with | Some { eexpr = TFunction { tf_expr = { eexpr = TBlock ([] | [{ eexpr = TReturn (Some { eexpr = TConst _ })}]) } } } | None -> - let name = prefix ^ String.lowercase (Str.global_replace (Str.regexp "[A-Z]+") "_\\0" f.cf_name) in + let name = prefix ^ String.lowercase_ascii (Str.global_replace (Str.regexp "[A-Z]+") "_\\0" f.cf_name) in f.cf_meta <- (Meta.HlNative, [(EConst (String(lib,SDoubleQuotes)),p);(EConst (String(name,SDoubleQuotes)),p)], p) :: f.cf_meta; | _ -> ()) | _ -> () @@ -4153,7 +4186,7 @@ let generate com = in if Path.file_extension com.file = "c" then begin - let gnames = Array.create (Array.length code.globals) "" in + let gnames = Array.make (Array.length code.globals) "" in PMap.iter (fun n i -> gnames.(i) <- n) ctx.cglobals.map; if not (Common.defined com Define.SourceHeader) then begin let version_major = com.version / 1000 in diff --git a/src/generators/genjvm.ml b/src/generators/genjvm.ml index 5ff17668e28..05c4e54545d 100644 --- a/src/generators/genjvm.ml +++ b/src/generators/genjvm.ml @@ -31,6 +31,7 @@ open JvmSignature open JvmMethod open JvmBuilder open Genshared +open Tanon_identification (* Note: This module is the bridge between Haxe structures and JVM structures. No module in generators/jvm should reference any Haxe-specific type. *) diff --git a/src/generators/genphp7.ml b/src/generators/genphp7.ml index 514acd4a3b3..288a9168cd3 100644 --- a/src/generators/genphp7.ml +++ b/src/generators/genphp7.ml @@ -15,8 +15,8 @@ open Sourcemaps *) let escape_bin s = let b = Buffer.create 0 in - for i = 0 to String.length s - 1 do - match Char.code (String.unsafe_get s i) with + for i = 0 to ExtString.String.length s - 1 do + match Char.code (ExtString.String.unsafe_get s i) with | c when c = Char.code('\\') || c = Char.code('"') || c = Char.code('$') -> Buffer.add_string b "\\"; Buffer.add_char b (Char.chr c) @@ -46,7 +46,7 @@ let write_resource dir name data = *) let copy_file src dst = let buffer_size = 8192 in - let buffer = String.create buffer_size in + let buffer = ExtString.String.create buffer_size in let fd_in = Unix.openfile src [O_RDONLY] 0 in let fd_out = Unix.openfile dst [O_WRONLY; O_CREAT; O_TRUNC] 0o644 in let rec copy_loop () = @@ -196,7 +196,7 @@ end (** Check if specified string is a reserved word in PHP *) -let is_keyword str = Hashtbl.mem php_keywords_tbl (String.lowercase str) +let is_keyword str = Hashtbl.mem php_keywords_tbl (ExtString.String.lowercase str) (** Check if specified type is php.NativeArray @@ -531,10 +531,10 @@ let get_full_type_name ?(escape=false) ?(omit_first_slash=false) (type_path:path else "" :: get_real_path module_path in - (String.concat "\\" parts) ^ "\\" ^ type_name + (ExtString.String.concat "\\" parts) ^ "\\" ^ type_name in if escape then - String.escaped name + ExtString.String.escaped name else name @@ -618,7 +618,7 @@ let fix_call_args callee_type exprs = Escapes all "$" chars and encloses `str` into double quotes *) let quote_string str = - "\"" ^ (Str.global_replace (Str.regexp "\\$") "\\$" (String.escaped str)) ^ "\"" + "\"" ^ (Str.global_replace (Str.regexp "\\$") "\\$" (ExtString.String.escaped str)) ^ "\"" (** Check if specified field is a var with non-constant expression @@ -1296,21 +1296,21 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = Decrease indentation by one level *) method indent_less = - indentation <- String.make ((String.length indentation) - 1) '\t'; + indentation <- ExtString.String.make ((ExtString.String.length indentation) - 1) '\t'; (** Set indentation level (starting from zero for no indentation) *) method indent level = - indentation <- String.make level '\t'; + indentation <- ExtString.String.make level '\t'; (** Get indentation level (starting from zero for no indentation) *) - method get_indentation = String.length indentation + method get_indentation = ExtString.String.length indentation (** Set indentation level (starting from zero for no indentation) *) method set_indentation level = - indentation <- String.make level '\t' + indentation <- ExtString.String.make level '\t' (** Specify local var name declared in current scope *) @@ -1326,7 +1326,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = else if get_type_name type_path = "" then match get_module_path type_path with | [] -> "\\" - | module_path -> "\\" ^ (String.concat "\\" (get_real_path module_path)) ^ "\\" + | module_path -> "\\" ^ (ExtString.String.concat "\\" (get_real_path module_path)) ^ "\\" else begin let orig_type_path = type_path in let type_path = match type_path with (pack, name) -> (pack, get_real_name name) in @@ -1942,7 +1942,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = set_sourcemap_pointer sourcemap sm_pointer_before_body; let locals = vars#pop_captured in if List.length locals > 0 then begin - self#write ("unset($" ^ (String.concat ", $" locals) ^ ");\n"); + self#write ("unset($" ^ (ExtString.String.concat ", $" locals) ^ ");\n"); self#write_indentation end; self#write_bypassing_sourcemap body; @@ -2999,7 +2999,7 @@ class virtual type_builder ctx (wrapper:type_wrapper) = Returns generated file contents *) method get_contents = - if (String.length contents) = 0 then begin + if (ExtString.String.length contents) = 0 then begin self#write_declaration; writer#write_line " {"; (** opening bracket for a class *) self#write_body; @@ -3016,7 +3016,7 @@ class virtual type_builder ctx (wrapper:type_wrapper) = writer#write_statement ("require_once __DIR__.'/" ^ polyfills_file ^ "'"); writer#write_statement (boot_class ^ "::__hx__init()") end; - let haxe_class = match wrapper#get_type_path with (path, name) -> String.concat "." (path @ [name]) in + let haxe_class = match wrapper#get_type_path with (path, name) -> ExtString.String.concat "." (path @ [name]) in writer#write_statement (boot_class ^ "::registerClass(" ^ (self#get_name) ^ "::class, '" ^ haxe_class ^ "')"); self#write_rtti_meta; self#write_pre_hx_init; @@ -3051,7 +3051,7 @@ class virtual type_builder ctx (wrapper:type_wrapper) = writer#write "\n"; let namespace = self#get_namespace in if List.length namespace > 0 then - writer#write_line ("namespace " ^ (String.concat "\\" namespace) ^ ";\n"); + writer#write_line ("namespace " ^ (ExtString.String.concat "\\" namespace) ^ ";\n"); writer#write_use (** Generates PHP docblock and attributes to output buffer. @@ -3082,11 +3082,11 @@ class virtual type_builder ctx (wrapper:type_wrapper) = Writes description section of docblocks *) method write_doc_description (doc:string) = - let lines = Str.split (Str.regexp "\n") (String.trim doc) + let lines = Str.split (Str.regexp "\n") (ExtString.String.trim doc) and write_line line = - let trimmed = String.trim line in - if String.length trimmed > 0 then ( - if String.get trimmed 0 = '*' then + let trimmed = ExtString.String.trim line in + if ExtString.String.length trimmed > 0 then ( + if ExtString.String.get trimmed 0 = '*' then writer#write_line (" " ^ trimmed) else writer#write_line (" * " ^ trimmed) @@ -3554,7 +3554,7 @@ class class_builder ctx (cls:tclass) = cls.cl_implements in let interfaces = List.map use_interface unique in - writer#write (String.concat ", " interfaces); + writer#write (ExtString.String.concat ", " interfaces); end; (** Returns either user-defined constructor or creates empty constructor if instance initialization is required. @@ -3667,7 +3667,7 @@ class class_builder ctx (cls:tclass) = List.iter (fun field -> if not !required then - required := (String.lowercase field.cf_name = String.lowercase self#get_name) + required := (ExtString.String.lowercase field.cf_name = ExtString.String.lowercase self#get_name) ) (cls.cl_ordered_statics @ cls.cl_ordered_fields); !required @@ -3676,10 +3676,10 @@ class class_builder ctx (cls:tclass) = Writes `-D php-prefix` value as class constant PHP_PREFIX *) method private write_php_prefix () = - let prefix = String.concat "\\" ctx.pgc_prefix in + let prefix = ExtString.String.concat "\\" ctx.pgc_prefix in let indentation = writer#get_indentation in writer#indent 1; - writer#write_statement ("const PHP_PREFIX = \"" ^ (String.escaped prefix) ^ "\""); + writer#write_statement ("const PHP_PREFIX = \"" ^ (ExtString.String.escaped prefix) ^ "\""); writer#indent indentation (** Writes expressions for `__hx__init` method @@ -3998,8 +3998,8 @@ class generator (ctx:php_generator_context) = if front_dirs <> [] then ignore(create_dir_recursive (root_dir :: front_dirs)); let lib_path = - (String.concat "" (List.fold_left (fun acc s -> if s <> "." then "../" :: acc else acc) [] front_dirs)) - ^ (String.concat "/" self#get_lib_path) + (ExtString.String.concat "" (List.fold_left (fun acc s -> if s <> "." then "../" :: acc else acc) [] front_dirs)) + ^ (ExtString.String.concat "/" self#get_lib_path) in let channel = open_out (root_dir ^ "/" ^ filename) in output_string channel " true | _ -> false -open OverloadResolution - -type 'a path_field_mapping = { - pfm_path : path; - pfm_params : type_params; - pfm_fields : (string,tclass_field) PMap.t; - mutable pfm_converted : (string * 'a) list option; - pfm_arity : int; -} - -let count_fields pm = - PMap.fold (fun _ i -> i + 1) pm 0 - -let pfm_of_typedef td = match follow td.t_type with - | TAnon an -> { - pfm_path = td.t_path; - pfm_params = td.t_params; - pfm_fields = an.a_fields; - pfm_converted = None; - pfm_arity = count_fields an.a_fields; - } - | _ -> - die "" __LOC__ - -class ['a] tanon_identification (empty_path : string list * string) = - let is_normal_anon an = match !(an.a_status) with - | Closed | Const -> true - | _ -> false - in -object(self) - - val pfms = Hashtbl.create 0 - val pfm_by_arity = DynArray.create () - val mutable num = 0 - - method get_pfms = pfms - - method add_pfm (path : path) (pfm : 'a path_field_mapping) = - while DynArray.length pfm_by_arity <= pfm.pfm_arity do - DynArray.add pfm_by_arity (DynArray.create ()) - done; - DynArray.add (DynArray.get pfm_by_arity pfm.pfm_arity) pfm; - Hashtbl.replace pfms path pfm - - method unify (tc : Type.t) (pfm : 'a path_field_mapping) = - let check () = - let pair_up fields = - PMap.fold (fun cf acc -> - let cf' = PMap.find cf.cf_name fields in - (cf,cf') :: acc - ) pfm.pfm_fields [] - in - let monos = match follow tc with - | TInst(c,tl) -> - let pairs = pair_up c.cl_fields in - let monos = List.map (fun _ -> mk_mono()) pfm.pfm_params in - let map = apply_params pfm.pfm_params monos in - List.iter (fun (cf,cf') -> - if not (unify_kind cf'.cf_kind cf.cf_kind) then raise (Unify_error [Unify_custom "kind mismatch"]); - Type.unify (apply_params c.cl_params tl (monomorphs cf'.cf_params cf'.cf_type)) (map (monomorphs cf.cf_params cf.cf_type)) - ) pairs; - monos - | TAnon an1 -> - let fields = ref an1.a_fields in - let pairs = pair_up an1.a_fields in - let monos = List.map (fun _ -> mk_mono()) pfm.pfm_params in - let map = apply_params pfm.pfm_params monos in - List.iter (fun (cf,cf') -> - if not (unify_kind cf'.cf_kind cf.cf_kind) then raise (Unify_error [Unify_custom "kind mismatch"]); - fields := PMap.remove cf.cf_name !fields; - Type.type_eq EqDoNotFollowNull cf'.cf_type (map (monomorphs cf.cf_params cf.cf_type)) - ) pairs; - if not (PMap.is_empty !fields) then raise (Unify_error [Unify_custom "not enough fields"]); - monos - | _ -> - raise (Unify_error [Unify_custom "bad type"]) - in - (* Check if we applied Void to a return type parameter... (#3463) *) - List.iter (fun t -> match follow t with - | TMono r -> - Monomorph.bind r t_dynamic - | t -> - if Type.ExtType.is_void t then raise(Unify_error [Unify_custom "return mono"]) - ) monos - in - try - check() - with Not_found -> - raise (Unify_error []) - - method find_compatible (arity : int) (tc : Type.t) = - if arity >= DynArray.length pfm_by_arity then - raise Not_found; - let d = DynArray.get pfm_by_arity arity in - let l = DynArray.length d in - let rec loop i = - if i >= l then - raise Not_found; - let pfm = DynArray.unsafe_get d i in - try - self#unify tc pfm; - pfm - with Unify_error _ -> - loop (i + 1) - in - loop 0 - - method identify_typedef (td : tdef) = - let rec loop t = match t with - | TAnon an when is_normal_anon an && not (PMap.is_empty an.a_fields) -> - self#add_pfm td.t_path (pfm_of_typedef td) - | TMono {tm_type = Some t} -> - loop t - | TLazy f -> - loop (lazy_type f) - | t -> - () - in - loop td.t_type - - method identify (accept_anons : bool) (t : Type.t) = - match t with - | TType(td,tl) -> - begin try - Some (Hashtbl.find pfms td.t_path) - with Not_found -> - self#identify accept_anons (apply_typedef td tl) - end - | TMono {tm_type = Some t} -> - self#identify accept_anons t - | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> - self#identify accept_anons (Abstract.get_underlying_type a tl) - | TAbstract({a_path=([],"Null")},[t]) -> - self#identify accept_anons t - | TLazy f -> - self#identify accept_anons (lazy_type f) - | TAnon an when accept_anons && not (PMap.is_empty an.a_fields) -> - let arity = PMap.fold (fun cf i -> - Gencommon.replace_mono cf.cf_type; - i + 1 - ) an.a_fields 0 in - begin try - Some (self#find_compatible arity t) - with Not_found -> - let id = num in - num <- num + 1; - let path = (["haxe";"generated"],Printf.sprintf "Anon%i" id) in - let pfm = { - pfm_path = path; - pfm_params = []; - pfm_fields = an.a_fields; - pfm_converted = None; - pfm_arity = count_fields an.a_fields; - } in - self#add_pfm path pfm; - Some pfm - end; - | _ -> - None -end - type field_generation_info = { mutable has_this_before_super : bool; (* This is an ordered list of fields that are targets of super() calls which is determined during @@ -214,7 +53,8 @@ module Info = struct end open Info - +open OverloadResolution +open Tanon_identification class ['a] preprocessor (basic : basic_types) (convert : Type.t -> 'a) = let make_native cf = diff --git a/src/generators/genswf9.ml b/src/generators/genswf9.ml index 9e19e1f5566..68bf751eabc 100644 --- a/src/generators/genswf9.ml +++ b/src/generators/genswf9.ml @@ -645,7 +645,7 @@ let begin_switch ctx = constructs := (tag,ctx.infos.ipos) :: !constructs; in let fend() = - let cases = Array.create (!max + 1) 1 in + let cases = Array.make (!max + 1) 1 in List.iter (fun (tag,pos) -> Array.set cases tag (pos - switch_pos)) !constructs; DynArray.set ctx.code switch_index (HSwitch (1,Array.to_list cases)); branch(); diff --git a/src/generators/hl2c.ml b/src/generators/hl2c.ml index af03a261786..8462b035355 100644 --- a/src/generators/hl2c.ml +++ b/src/generators/hl2c.ml @@ -85,7 +85,7 @@ let sprintf = Printf.sprintf let keywords = let c_kwds = [ - "auto";"break";"case";"char";"const";"continue";"default";"do";"double";"else";"enum";"extern";"float";"for";"goto"; + "auto";"bool";"break";"case";"char";"const";"continue";"default";"do";"double";"else";"enum";"extern";"float";"for";"goto"; "if";"int";"long";"register";"return";"short";"signed";"sizeof";"static";"struct";"switch";"typedef";"union";"unsigned"; "void";"volatile";"while"; (* Values *) @@ -829,7 +829,7 @@ let generate_function ctx f = sexpr "%s = %s == 0 ? 0 : ((unsigned)%s) / ((unsigned)%s)" (reg r) (reg b) (reg a) (reg b) | OSMod (r,a,b) -> (match rtype r with - | HUI8 | HUI16 | HI32 -> + | HUI8 | HUI16 | HI32 | HI64 -> sexpr "%s = %s == 0 ? 0 : %s %% %s" (reg r) (reg b) (reg a) (reg b) | HF32 -> sexpr "%s = fmodf(%s,%s)" (reg r) (reg a) (reg b) @@ -1087,6 +1087,15 @@ let generate_function ctx f = sexpr "%s = %s + %s" (reg r) (reg r2) (reg off) | ONop _ -> () + | OPrefetch (r,fid,mode) -> + let expr = (if fid = 0 then reg r else (match rtype r with + | HObj o | HStruct o -> + let name, t = resolve_field o (fid - 1) in + Printf.sprintf "%s->%s" (reg r) name + | _ -> + Globals.die "" __LOC__ + )) in + sexpr "__hl_prefetch_m%d(%s)" mode expr ) f.code; flush_options (Array.length f.code); unblock(); @@ -1134,7 +1143,7 @@ let make_types_idents htypes = try PMap.find vp (!types_descs) with Not_found -> - let arr = Array.create (Array.length vp.vfields) ("",DSimple HVoid) in + let arr = Array.make (Array.length vp.vfields) ("",DSimple HVoid) in let td = DVirtual arr in types_descs := PMap.add vp td (!types_descs); Array.iteri (fun i (f,_,t) -> arr.(i) <- (f,make_desc t)) vp.vfields; diff --git a/src/generators/hlcode.ml b/src/generators/hlcode.ml index 733a6b10e05..d40313f9c26 100644 --- a/src/generators/hlcode.ml +++ b/src/generators/hlcode.ml @@ -201,6 +201,7 @@ type opcode = | ORefData of reg * reg | ORefOffset of reg * reg * reg | ONop of string + | OPrefetch of reg * field index * int type fundecl = { fpath : string * string; @@ -572,6 +573,8 @@ let ostr fstr o = | ORefData (r,d) -> Printf.sprintf "refdata %d, %d" r d | ORefOffset (r,r2,off) -> Printf.sprintf "refoffset %d, %d, %d" r r2 off | ONop s -> if s = "" then "nop" else "nop " ^ s + | OPrefetch (r,f,mode) -> Printf.sprintf "prefetch %d[%d] %d" r f mode + let fundecl_name f = if snd f.fpath = "" then "fun$" ^ (string_of_int f.findex) else (fst f.fpath) ^ "." ^ (snd f.fpath) let dump pr code = diff --git a/src/generators/hlinterp.ml b/src/generators/hlinterp.ml index f6fc7f32fd0..baba96be4d9 100644 --- a/src/generators/hlinterp.ml +++ b/src/generators/hlinterp.ml @@ -1111,7 +1111,7 @@ let interp ctx f args = (match rtype r with | HEnum e -> let _, _, fl = e.efields.(f) in - let vl = Array.create (Array.length fl) VUndef in + let vl = Array.make (Array.length fl) VUndef in set r (VEnum (e, f, vl)) | _ -> Globals.die "" __LOC__ ) @@ -1154,7 +1154,7 @@ let interp ctx f args = (match get r2, get off with | VRef (RArray (a,pos),t), VInt i -> set r (VRef (RArray (a,pos + Int32.to_int i),t)) | _ -> Globals.die "" __LOC__) - | ONop _ -> + | ONop _ | OPrefetch _ -> () ); loop() @@ -1257,7 +1257,7 @@ let load_native ctx lib name t = | _ -> Globals.die "" __LOC__) | "alloc_array" -> (function - | [VType t;VInt i] -> VArray (Array.create (int i) (default t),t) + | [VType t;VInt i] -> VArray (Array.make (int i) (default t),t) | _ -> Globals.die "" __LOC__) | "alloc_obj" -> (function @@ -1347,7 +1347,7 @@ let load_native ctx lib name t = | "math_asin" -> (function [VFloat f] -> VFloat (asin f) | _ -> Globals.die "" __LOC__) | "math_atan" -> (function [VFloat f] -> VFloat (atan f) | _ -> Globals.die "" __LOC__) | "math_atan2" -> (function [VFloat a; VFloat b] -> VFloat (atan2 a b) | _ -> Globals.die "" __LOC__) - | "math_log" -> (function [VFloat f] -> VFloat (Pervasives.log f) | _ -> Globals.die "" __LOC__) + | "math_log" -> (function [VFloat f] -> VFloat (Stdlib.log f) | _ -> Globals.die "" __LOC__) | "math_exp" -> (function [VFloat f] -> VFloat (exp f) | _ -> Globals.die "" __LOC__) | "math_pow" -> (function [VFloat a; VFloat b] -> VFloat (a ** b) | _ -> Globals.die "" __LOC__) | "parse_int" -> @@ -1539,7 +1539,7 @@ let load_native ctx lib name t = | "Darwin" -> "Mac" | n -> n ) in - Pervasives.ignore (Process_helper.close_process_in_pid (ic, pid)); + Stdlib.ignore (Process_helper.close_process_in_pid (ic, pid)); cached_sys_name := Some uname; uname) | "Win32" | "Cygwin" -> "Windows" @@ -2147,7 +2147,7 @@ let add_code ctx code = ctx.t_globals <- globals; (* expand function table *) let nfunctions = Array.length code.functions + Array.length code.natives in - let functions = Array.create nfunctions (FNativeFun ("",(fun _ -> Globals.die "" __LOC__),HDyn)) in + let functions = Array.make nfunctions (FNativeFun ("",(fun _ -> Globals.die "" __LOC__),HDyn)) in Array.blit ctx.t_functions 0 functions 0 (Array.length ctx.t_functions); let rec loop i = if i = Array.length code.natives then () else @@ -2191,7 +2191,7 @@ let add_code ctx code = (* ------------------------------- CHECK ---------------------------------------------- *) let check code macros = - let ftypes = Array.create (Array.length code.natives + Array.length code.functions) HVoid in + let ftypes = Array.make (Array.length code.natives + Array.length code.functions) HVoid in let is_native_fun = Hashtbl.create 0 in let check_fun f = @@ -2436,7 +2436,7 @@ let check code macros = | ORethrow r -> reg r HDyn | OGetArray (v,a,i) -> - reg a HArray; + (match rtype a with HAbstract ("hl_carray",_) -> () | _ -> reg a HArray); reg i HI32; ignore(rtype v); | OGetUI8 (r,b,p) | OGetUI16(r,b,p) -> @@ -2466,7 +2466,7 @@ let check code macros = ignore(rtype a); ignore(rtype b); | OArraySize (r,a) -> - reg a HArray; + (match rtype a with HAbstract ("hl_carray",_) -> () | _ -> reg a HArray); reg r HI32 | OType (r,_) -> reg r HType @@ -2547,6 +2547,8 @@ let check code macros = reg off HI32; | ONop _ -> (); + | OPrefetch (r,f,_) -> + if f = 0 then ignore(rtype r) else ignore(tfield r (f - 1) false) ) f.code (* TODO : check that all path correctly initialize NULL values and reach a return *) in diff --git a/src/generators/hlopt.ml b/src/generators/hlopt.ml index 2e5bd20c4c6..c11db0161aa 100644 --- a/src/generators/hlopt.ml +++ b/src/generators/hlopt.ml @@ -164,6 +164,8 @@ let opcode_fx frw op = write r; | ONop _ -> () + | OPrefetch (r,_,_) -> + read r let opcode_eq a b = match a, b with @@ -432,6 +434,9 @@ let opcode_map read write op = ORefOffset (write r,r2,off); | ONop _ -> op + | OPrefetch (r, fid, mode) -> + let r2 = read r in + OPrefetch (r2, fid, mode) (* build code graph *) @@ -875,6 +880,11 @@ let _optimize (f:fundecl) = | OGetThis (r,fid) when (match f.regs.(r) with HStruct _ -> true | _ -> false) -> do_write r; if is_packed_field 0 fid then state.(r).rnullcheck <- true; + | OGetArray (r,arr,idx) -> + do_read arr; + do_read idx; + do_write r; + (match f.regs.(arr) with HAbstract _ -> state.(r).rnullcheck <- true | _ -> ()); | _ -> opcode_fx (fun r read -> if read then do_read r else do_write r diff --git a/src/macro/eval/evalArray.ml b/src/macro/eval/evalArray.ml index ceb58758153..fb70be03a5c 100644 --- a/src/macro/eval/evalArray.ml +++ b/src/macro/eval/evalArray.ml @@ -200,6 +200,6 @@ let resize a l = set a (l - 1) vnull; () end else if a.alength > l then begin - ignore(splice a l (a.alength - l) a.alength); - () + Array.fill a.avalues l (a.alength - l) vnull; + a.alength <- l; end else () diff --git a/src/macro/eval/evalJit.ml b/src/macro/eval/evalJit.ml index c9e7d35c958..d2c21a539a1 100644 --- a/src/macro/eval/evalJit.ml +++ b/src/macro/eval/evalJit.ml @@ -230,7 +230,7 @@ and jit_expr jit return e = let hasret = jit_closure.has_nonfinal_return in let eci = get_env_creation jit_closure false tf.tf_expr.epos.pfile (EKLocalFunction jit.num_closures) in let captures = Hashtbl.fold (fun vid (i,declared) acc -> (i,vid,declared) :: acc) jit_closure.captures [] in - let captures = List.sort (fun (i1,_,_) (i2,_,_) -> Pervasives.compare i1 i2) captures in + let captures = List.sort (fun (i1,_,_) (i2,_,_) -> Stdlib.compare i1 i2) captures in (* Check if the out-of-scope var is in the outer scope because otherwise we have to promote outwards. *) List.iter (fun var -> ignore(get_capture_slot jit var)) jit_closure.captures_outside_scope; let captures = ExtList.List.filter_map (fun (i,vid,declared) -> diff --git a/src/macro/eval/evalStdLib.ml b/src/macro/eval/evalStdLib.ml index 90b3d157340..ae09bcbfef8 100644 --- a/src/macro/eval/evalStdLib.ml +++ b/src/macro/eval/evalStdLib.ml @@ -289,7 +289,7 @@ module StdBytes = struct let compare = vifun1 (fun vthis other -> let this = this vthis in let other = decode_bytes other in - vint (Pervasives.compare this other) + vint (Stdlib.compare this other) ) let fastGet = vfun2 (fun b pos -> @@ -1694,13 +1694,13 @@ module StdMath = struct let ceil = vfun1 (fun v -> match v with VInt32 _ -> v | _ -> vint32 (to_int (ceil (num v)))) let cos = vfun1 (fun v -> vfloat (cos (num v))) let exp = vfun1 (fun v -> vfloat (exp (num v))) - let fceil = vfun1 (fun v -> vfloat (Pervasives.ceil (num v))) - let ffloor = vfun1 (fun v -> vfloat (Pervasives.floor (num v))) + let fceil = vfun1 (fun v -> vfloat (Stdlib.ceil (num v))) + let ffloor = vfun1 (fun v -> vfloat (Stdlib.floor (num v))) let floor = vfun1 (fun v -> match v with VInt32 _ -> v | _ -> vint32 (to_int (floor (num v)))) - let fround = vfun1 (fun v -> vfloat (Pervasives.floor (num v +. 0.5))) + let fround = vfun1 (fun v -> vfloat (Stdlib.floor (num v +. 0.5))) let isFinite = vfun1 (fun v -> vbool (match v with VFloat f -> f <> infinity && f <> neg_infinity && f = f | _ -> true)) let isNaN = vfun1 (fun v -> vbool (match v with VFloat f -> f <> f | VInt32 _ -> false | _ -> true)) - let log = vfun1 (fun v -> vfloat (Pervasives.log (num v))) + let log = vfun1 (fun v -> vfloat (Stdlib.log (num v))) let max = vfun2 (fun a b -> let a = num a in @@ -1716,7 +1716,7 @@ module StdMath = struct let pow = vfun2 (fun a b -> vfloat ((num a) ** (num b))) let random = vfun0 (fun () -> vfloat (Random.State.float random 1.)) - let round = vfun1 (fun v -> match v with VInt32 _ -> v | _ -> vint32 (to_int (Pervasives.floor (num v +. 0.5)))) + let round = vfun1 (fun v -> match v with VInt32 _ -> v | _ -> vint32 (to_int (Stdlib.floor (num v +. 0.5)))) let sin = vfun1 (fun v -> vfloat (sin (num v))) let sqrt = vfun1 (fun v -> @@ -2690,7 +2690,7 @@ module StdSys = struct | "Darwin" -> "Mac" | n -> n ) in - Pervasives.ignore (Process_helper.close_process_in_pid (ic, pid)); + Stdlib.ignore (Process_helper.close_process_in_pid (ic, pid)); cached_sys_name := Some uname; uname) | "Win32" | "Cygwin" -> "Windows" @@ -2735,10 +2735,12 @@ module StdThread = struct vnull ) - let kill = vifun0 (fun vthis -> - Thread.kill (this vthis).tthread; - vnull - ) + (* Thread.kill has been marked deprecated (because unstable or even not working at all) for a while, and removed in ocaml 5 *) + (* See also https://github.com/HaxeFoundation/haxe/issues/5800 *) + (* let kill = vifun0 (fun vthis -> *) + (* Thread.kill (this vthis).tthread; *) + (* vnull *) + (* ) *) let self = vfun0 (fun () -> let eval = get_eval (get_ctx()) in @@ -3062,7 +3064,7 @@ module StdUtf8 = struct let compare = vfun2 (fun a b -> let a = decode_string a in let b = decode_string b in - vint (Pervasives.compare a b) + vint (Stdlib.compare a b) ) let decode = vfun1 (fun s -> @@ -3728,7 +3730,7 @@ let init_standard_library builtins = "id",StdThread.id; "get_events",StdThread.get_events; "set_events",StdThread.set_events; - "kill",StdThread.kill; + (* "kill",StdThread.kill; *) "sendMessage",StdThread.sendMessage; ]; init_fields builtins (["sys";"thread"],"Tls") [] [ diff --git a/src/optimization/analyzerTexpr.ml b/src/optimization/analyzerTexpr.ml index 53abbf17e02..d6e0f927014 100644 --- a/src/optimization/analyzerTexpr.ml +++ b/src/optimization/analyzerTexpr.ml @@ -240,7 +240,7 @@ module TexprFilter = struct let e_if eo = mk (TIf(e_not,e_break,eo)) com.basic.tvoid p in let rec map_continue e = match e.eexpr with | TContinue -> - Texpr.duplicate_tvars (e_if (Some e)) + Texpr.duplicate_tvars e_identity (e_if (Some e)) | TWhile _ | TFor _ -> e | _ -> diff --git a/src/optimization/inline.ml b/src/optimization/inline.ml index 5157d03e78a..244c70cd0a6 100644 --- a/src/optimization/inline.ml +++ b/src/optimization/inline.ml @@ -506,14 +506,14 @@ class inline_state ctx ethis params cf f p = object(self) | VIInline -> begin match e'.eexpr with (* If we inline a function expression, we have to duplicate its locals. *) - | TFunction _ -> Texpr.duplicate_tvars e' + | TFunction _ -> Texpr.duplicate_tvars e_identity e' | TCast(e1,None) when in_assignment -> e1 | _ -> e' end | VIInlineIfCalled when in_call -> (* We allow inlining function expressions into call-places. However, we have to substitute their locals to avoid duplicate declarations. *) - Texpr.duplicate_tvars e' + Texpr.duplicate_tvars e_identity e' | _ -> e end with Not_found -> diff --git a/src/optimization/inlineConstructors.ml b/src/optimization/inlineConstructors.ml index 63cc3f926f5..11fa081c4ab 100644 --- a/src/optimization/inlineConstructors.ml +++ b/src/optimization/inlineConstructors.ml @@ -495,7 +495,7 @@ let inline_constructors ctx original_e = | IOFInlineMethod(io,io_var,c,tl,cf,tf) -> let argvs, pl = analyze_call_args call_args in io.io_dependent_vars <- io.io_dependent_vars @ argvs; - io.io_has_untyped <- io.io_has_untyped or (Meta.has Meta.HasUntyped cf.cf_meta); + io.io_has_untyped <- io.io_has_untyped || (Meta.has Meta.HasUntyped cf.cf_meta); let e = Inline.type_inline ctx cf tf (mk (TLocal io_var.iv_var) (TInst (c,tl)) e.epos) pl e.etype None e.epos true in let e = mark_ctors e in io.io_inline_methods <- io.io_inline_methods @ [e]; diff --git a/src/syntax/grammar.mly b/src/syntax/grammar.mly index 8ff085035e6..31cf8917a6a 100644 --- a/src/syntax/grammar.mly +++ b/src/syntax/grammar.mly @@ -963,6 +963,9 @@ and parse_class_field tdecl s = | [< '(Kwd Final,p1) >] -> check_redundant_var p1 s; begin match s with parser + | [< opt,name = questionable_dollar_ident; '(POpen,_); i1 = property_ident; '(Comma,_); i2 = property_ident; '(PClose,_); t = popt parse_type_hint; e,p2 = parse_var_field_assignment >] -> + let meta = check_optional opt name in + name,punion p1 p2,FProp(i1,i2,t,e),(al @ [AFinal,p1]),meta | [< opt,name = questionable_dollar_ident; t = popt parse_type_hint; e,p2 = parse_var_field_assignment >] -> let meta = check_optional opt name in name,punion p1 p2,FVar(t,e),(al @ [AFinal,p1]),meta @@ -1235,6 +1238,8 @@ and parse_array_decl p1 s = and parse_var_decl_head final s = let meta = parse_meta s in match s with parser + | [< name, p = dollar_ident; '(POpen,p1); _ = property_ident; '(Comma,_); _ = property_ident; '(PClose,p2); t = popt parse_type_hint >] -> + syntax_error (Custom "Cannot define property accessors for local vars") ~pos:(Some (punion p1 p2)) s (meta,name,final,t,p) | [< name, p = dollar_ident; t = popt parse_type_hint >] -> (meta,name,final,t,p) | [< >] -> (* This nonsense is here for the var @ case in issue #9639 *) diff --git a/src/typing/calls.ml b/src/typing/calls.ml index ef39f73a99c..b9c0f07117b 100644 --- a/src/typing/calls.ml +++ b/src/typing/calls.ml @@ -214,8 +214,8 @@ let rec acc_get ctx g = | AKUsingAccessor sea | AKUsingField sea when ctx.in_display -> (* Generate a TField node so we can easily match it for position/usage completion (issue #1968) *) let e_field = FieldAccess.get_field_expr sea.se_access FGet in - (* TODO *) - (* let ec = {ec with eexpr = (TMeta((Meta.StaticExtension,[],null_pos),ec))} in *) + let id,_ = store_typed_expr ctx.com sea.se_this e_field.epos in + let e_field = {e_field with eexpr = (TMeta((Meta.StaticExtension,[make_stored_id_expr id e_field.epos],null_pos),e_field))} in let t = match follow e_field.etype with | TFun (_ :: args,ret) -> TFun(args,ret) | t -> t diff --git a/src/typing/forLoop.ml b/src/typing/forLoop.ml index a759d65772d..d42a8a7cde7 100644 --- a/src/typing/forLoop.ml +++ b/src/typing/forLoop.ml @@ -326,7 +326,7 @@ module IterationKind = struct | _ -> map_expr loop e in let e2 = loop e2 in - Texpr.duplicate_tvars e2 + Texpr.duplicate_tvars e_identity e2 ) in mk (TBlock el) t_void p | IteratorIntConst(a,b,ascending) -> @@ -367,7 +367,7 @@ module IterationKind = struct let el = List.map (fun e -> let ev = mk (TVar(v,Some e)) t_void e.epos in let e = concat ev e2 in - Texpr.duplicate_tvars e + Texpr.duplicate_tvars e_identity e ) el in mk (TBlock el) t_void p | IteratorArray | IteratorArrayAccess -> diff --git a/src/typing/generic.ml b/src/typing/generic.ml index 58ad1a18dbb..5dacd82cd8c 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -16,57 +16,64 @@ type generic_context = { mutable mg : module_def option; } -let generic_check_const_expr ctx t = - match follow t with - | TInst({cl_kind = KExpr e},_) -> - let e = type_expr {ctx with locals = PMap.empty} e WithType.value in - e.etype,Some e - | _ -> t,None - let make_generic ctx ps pt p = - let rec loop l1 l2 = - match l1, l2 with - | [] , [] -> [] - | ({ttp_type=TLazy f} as tp) :: l1, _ -> loop ({tp with ttp_type=lazy_type f} :: l1) l2 - | tp1 :: l1 , t2 :: l2 -> - let t,eo = generic_check_const_expr ctx t2 in - (tp1.ttp_type,(t,eo)) :: loop l1 l2 - | _ -> die "" __LOC__ + let subst s = "_" ^ string_of_int (Char.code (String.get (Str.matched_string s) 0)) ^ "_" in + let ident_safe = Str.global_substitute (Str.regexp "[^a-zA-Z0-9_]") subst in + let s_type_path_underscore (p,s) = match p with [] -> s | _ -> String.concat "_" p ^ "_" ^ s in + let process t = + let rec loop top t = match t with + | TInst(c,tl) -> + begin match c.cl_kind with + | KExpr e -> + let name = ident_safe (Ast.Printer.s_expr e) in + let e = type_expr {ctx with locals = PMap.empty} e WithType.value in + name,(e.etype,Some e) + | _ -> + ((ident_safe (s_type_path_underscore c.cl_path)) ^ (loop_tl top tl),(t,None)) + end + | TType (td,tl) -> + (s_type_path_underscore td.t_path) ^ (loop_tl top tl),(t,None) + | TEnum(en,tl) -> + (s_type_path_underscore en.e_path) ^ (loop_tl top tl),(t,None) + | TAnon(a) -> + "anon_" ^ String.concat "_" (PMap.foldi (fun s f acc -> (s ^ "_" ^ (loop_deep (follow f.cf_type))) :: acc) a.a_fields []),(t,None) + | TFun(args, return_type) -> + ("func_" ^ (String.concat "_" (List.map (fun (_, _, t) -> loop_deep t) args)) ^ "_" ^ (loop_deep return_type)),(t,None) + | TAbstract(a,tl) -> + (s_type_path_underscore a.a_path) ^ (loop_tl top tl),(t,None) + | TDynamic _ -> + "Dynamic",(t,None) + | TMono { tm_type = None } -> + if not top then + "_",(t,None) + else + raise Exit + | TMono { tm_type = Some t} -> + loop top t + | TLazy f -> + loop top (lazy_type f) + and loop_tl top tl = match tl with + | [] -> "" + | tl -> "_" ^ String.concat "_" (List.map (fun t -> fst (loop top t)) tl) + and loop_deep t = + fst (loop false t) + in + loop true t in - let name = - String.concat "_" (List.map2 (fun {ttp_name=s} t -> - let subst s = "_" ^ string_of_int (Char.code (String.get (Str.matched_string s) 0)) ^ "_" in - let ident_safe = Str.global_substitute (Str.regexp "[^a-zA-Z0-9_]") subst in - let s_type_path_underscore (p,s) = match p with [] -> s | _ -> String.concat "_" p ^ "_" ^ s in - let rec loop top t = match t with - | TInst(c,tl) -> (match c.cl_kind with - | KExpr e -> ident_safe (Ast.Printer.s_expr e) - | _ -> (ident_safe (s_type_path_underscore c.cl_path)) ^ (loop_tl top tl)) - | TType (td,tl) -> (s_type_path_underscore td.t_path) ^ (loop_tl top tl) - | TEnum(en,tl) -> (s_type_path_underscore en.e_path) ^ (loop_tl top tl) - | TAnon(a) -> "anon_" ^ String.concat "_" (PMap.foldi (fun s f acc -> (s ^ "_" ^ (loop false (follow f.cf_type))) :: acc) a.a_fields []) - | TFun(args, return_type) -> "func_" ^ (String.concat "_" (List.map (fun (_, _, t) -> loop false t) args)) ^ "_" ^ (loop false return_type) - | TAbstract(a,tl) -> (s_type_path_underscore a.a_path) ^ (loop_tl top tl) - | _ when not top -> - follow_or t top (fun() -> "_") (* allow unknown/incompatible types as type parameters to retain old behavior *) - | TMono { tm_type = None } -> raise (Generic_Exception (("Could not determine type for parameter " ^ s), p)) - | TDynamic _ -> "Dynamic" - | t -> - follow_or t top (fun() -> raise (Generic_Exception (("Unsupported type parameter: " ^ (s_type (print_context()) t) ^ ")"), p))) - and loop_tl top tl = match tl with - | [] -> "" - | tl -> "_" ^ String.concat "_" (List.map (loop top) tl) - and follow_or t top or_fn = - let ft = follow_once t in - if ft == t then or_fn() - else loop top ft - in - loop true t - ) ps pt) + let rec loop acc_name acc_subst ttpl tl = match ttpl,tl with + | ttp :: ttpl,t :: tl -> + let name,t = try process t with Exit -> raise (Generic_Exception (("Could not determine type for parameter " ^ ttp.ttp_name), p)) in + loop (name :: acc_name) ((follow ttp.ttp_type,t) :: acc_subst) ttpl tl + | [],[] -> + let name = String.concat "_" (List.rev acc_name) in + name,acc_subst + | _ -> + die "" __LOC__ in + let name,subst = loop [] [] ps pt in { ctx = ctx; - subst = loop ps pt; + subst = subst; name = name; p = p; mg = None; diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index 856c1e747ee..eb25221c6f4 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -606,8 +606,8 @@ and flush_macro_context mint mctx = mctx.com.Common.modules <- modules; (* we should maybe ensure that all filters in Main are applied. Not urgent atm *) let expr_filters = [ - "local_statics",Filters.LocalStatic.run mctx; "handle_abstract_casts",AbstractCast.handle_abstract_casts mctx; + "local_statics",Filters.LocalStatic.run mctx; "Exceptions",Exceptions.filter mctx; "captured_vars",CapturedVars.captured_vars mctx.com; ] in @@ -1053,7 +1053,3 @@ let interpret ctx = let setup() = Interp.setup Interp.macro_api - -let type_stored_expr ctx e1 = - let id = match e1 with (EConst (Int (s, _)),_) -> int_of_string s | _ -> die "" __LOC__ in - get_stored_typed_expr ctx.com id diff --git a/src/typing/matcher/exprToPattern.ml b/src/typing/matcher/exprToPattern.ml index 491bd6d9126..99895207b73 100644 --- a/src/typing/matcher/exprToPattern.ml +++ b/src/typing/matcher/exprToPattern.ml @@ -436,7 +436,7 @@ let rec make pctx toplevel t e = ignore(TyperDisplay.handle_edisplay ctx e (display_mode()) MGet (WithType.with_type t)); pat | EMeta((Meta.StoredTypedExpr,_,_),e1) -> - let e1 = MacroContext.type_stored_expr ctx e1 in + let e1 = TyperBase.type_stored_expr ctx e1 in loop (TExprToExpr.convert_expr e1) | _ -> fail() diff --git a/src/typing/matcher/texprConverter.ml b/src/typing/matcher/texprConverter.ml index debd46a3da2..8b234e6f9bd 100644 --- a/src/typing/matcher/texprConverter.ml +++ b/src/typing/matcher/texprConverter.ml @@ -193,7 +193,7 @@ let report_not_exhaustive v_lookup e_subject unmatched = in let s = match unmatched with | [] -> "_" - | _ -> String.concat " | " (List.sort Pervasives.compare sl) + | _ -> String.concat " | " (List.sort Stdlib.compare sl) in raise_typing_error (Printf.sprintf "Unmatched patterns: %s" (s_subject v_lookup s e_subject)) e_subject.epos @@ -393,4 +393,4 @@ let to_texpr ctx t_switch with_type dt = | None -> raise_typing_error "Unmatched patterns: _" p; | Some e -> - Texpr.duplicate_tvars e + Texpr.duplicate_tvars e_identity e diff --git a/src/typing/tanon_identification.ml b/src/typing/tanon_identification.ml new file mode 100644 index 00000000000..8af805fe9ee --- /dev/null +++ b/src/typing/tanon_identification.ml @@ -0,0 +1,177 @@ +open Globals +open Type + +let rec replace_mono t = + match t with + | TMono t -> + (match t.tm_type with + | None -> Monomorph.bind t t_dynamic + | Some _ -> ()) + | TEnum (_,p) | TInst (_,p) | TType (_,p) | TAbstract (_,p) -> + List.iter replace_mono p + | TFun (args,ret) -> + List.iter (fun (_,_,t) -> replace_mono t) args; + replace_mono ret + | TAnon _ + | TDynamic _ -> () + | TLazy f -> + replace_mono (lazy_type f) + +type 'a path_field_mapping = { + pfm_path : path; + pfm_params : type_params; + pfm_fields : (string,tclass_field) PMap.t; + mutable pfm_converted : (string * 'a) list option; + pfm_arity : int; +} + +let count_fields pm = + PMap.fold (fun _ i -> i + 1) pm 0 + +let pfm_of_typedef td = match follow td.t_type with + | TAnon an -> { + pfm_path = td.t_path; + pfm_params = td.t_params; + pfm_fields = an.a_fields; + pfm_converted = None; + pfm_arity = count_fields an.a_fields; + } + | _ -> + die "" __LOC__ + +class ['a] tanon_identification (empty_path : string list * string) = + let is_normal_anon an = match !(an.a_status) with + | Closed | Const -> true + | _ -> false + in +object(self) + + val pfms = Hashtbl.create 0 + val pfm_by_arity = DynArray.create () + val mutable num = 0 + + method get_pfms = pfms + + method add_pfm (path : path) (pfm : 'a path_field_mapping) = + while DynArray.length pfm_by_arity <= pfm.pfm_arity do + DynArray.add pfm_by_arity (DynArray.create ()) + done; + DynArray.add (DynArray.get pfm_by_arity pfm.pfm_arity) pfm; + Hashtbl.replace pfms path pfm + + method unify (tc : Type.t) (pfm : 'a path_field_mapping) = + let check () = + let pair_up fields = + PMap.fold (fun cf acc -> + let cf' = PMap.find cf.cf_name fields in + (cf,cf') :: acc + ) pfm.pfm_fields [] + in + let monos = match follow tc with + | TInst(c,tl) -> + let pairs = pair_up c.cl_fields in + let monos = List.map (fun _ -> mk_mono()) pfm.pfm_params in + let map = apply_params pfm.pfm_params monos in + List.iter (fun (cf,cf') -> + if not (unify_kind cf'.cf_kind cf.cf_kind) then raise (Unify_error [Unify_custom "kind mismatch"]); + Type.unify (apply_params c.cl_params tl (monomorphs cf'.cf_params cf'.cf_type)) (map (monomorphs cf.cf_params cf.cf_type)) + ) pairs; + monos + | TAnon an1 -> + let fields = ref an1.a_fields in + let pairs = pair_up an1.a_fields in + let monos = List.map (fun _ -> mk_mono()) pfm.pfm_params in + let map = apply_params pfm.pfm_params monos in + List.iter (fun (cf,cf') -> + if not (unify_kind cf'.cf_kind cf.cf_kind) then raise (Unify_error [Unify_custom "kind mismatch"]); + fields := PMap.remove cf.cf_name !fields; + Type.type_eq EqDoNotFollowNull cf'.cf_type (map (monomorphs cf.cf_params cf.cf_type)) + ) pairs; + if not (PMap.is_empty !fields) then raise (Unify_error [Unify_custom "not enough fields"]); + monos + | _ -> + raise (Unify_error [Unify_custom "bad type"]) + in + (* Check if we applied Void to a return type parameter... (#3463) *) + List.iter (fun t -> match follow t with + | TMono r -> + Monomorph.bind r t_dynamic + | t -> + if Type.ExtType.is_void t then raise(Unify_error [Unify_custom "return mono"]) + ) monos + in + try + check() + with Not_found -> + raise (Unify_error []) + + method find_compatible (arity : int) (tc : Type.t) = + if arity >= DynArray.length pfm_by_arity then + raise Not_found; + let d = DynArray.get pfm_by_arity arity in + let l = DynArray.length d in + let rec loop i = + if i >= l then + raise Not_found; + let pfm = DynArray.unsafe_get d i in + try + self#unify tc pfm; + pfm + with Unify_error _ -> + loop (i + 1) + in + loop 0 + + method identify_typedef (td : tdef) = + let rec loop t = match t with + | TAnon an when is_normal_anon an && not (PMap.is_empty an.a_fields) -> + self#add_pfm td.t_path (pfm_of_typedef td) + | TMono {tm_type = Some t} -> + loop t + | TLazy f -> + loop (lazy_type f) + | t -> + () + in + loop td.t_type + + method identify (accept_anons : bool) (t : Type.t) = + match t with + | TType(td,tl) -> + begin try + Some (Hashtbl.find pfms td.t_path) + with Not_found -> + self#identify accept_anons (apply_typedef td tl) + end + | TMono {tm_type = Some t} -> + self#identify accept_anons t + | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> + self#identify accept_anons (Abstract.get_underlying_type a tl) + | TAbstract({a_path=([],"Null")},[t]) -> + self#identify accept_anons t + | TLazy f -> + self#identify accept_anons (lazy_type f) + | TAnon an when accept_anons && not (PMap.is_empty an.a_fields) -> + let arity = PMap.fold (fun cf i -> + replace_mono cf.cf_type; + i + 1 + ) an.a_fields 0 in + begin try + Some (self#find_compatible arity t) + with Not_found -> + let id = num in + num <- num + 1; + let path = (["haxe";"generated"],Printf.sprintf "Anon%i" id) in + let pfm = { + pfm_path = path; + pfm_params = []; + pfm_fields = an.a_fields; + pfm_converted = None; + pfm_arity = count_fields an.a_fields; + } in + self#add_pfm path pfm; + Some pfm + end; + | _ -> + None +end \ No newline at end of file diff --git a/src/typing/typeloadCheck.ml b/src/typing/typeloadCheck.ml index 8cc8e1f0a56..ffeef145dfd 100644 --- a/src/typing/typeloadCheck.ml +++ b/src/typing/typeloadCheck.ml @@ -319,7 +319,7 @@ let check_module_types ctx m p t = let t = t_infos t in try let path2 = ctx.com.type_to_module#find t.mt_path in - if m.m_path <> path2 && String.lowercase (s_type_path path2) = String.lowercase (s_type_path m.m_path) then raise_typing_error ("Module " ^ s_type_path path2 ^ " is loaded with a different case than " ^ s_type_path m.m_path) p; + if m.m_path <> path2 && String.lowercase_ascii (s_type_path path2) = String.lowercase_ascii (s_type_path m.m_path) then raise_typing_error ("Module " ^ s_type_path path2 ^ " is loaded with a different case than " ^ s_type_path m.m_path) p; let m2 = ctx.com.module_lut#find path2 in let hex1 = Digest.to_hex m.m_extra.m_sign in let hex2 = Digest.to_hex m2.m_extra.m_sign in diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index 91906056c48..9d7a4ee773f 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -93,6 +93,9 @@ module FieldError = struct let invalid_modifier_only com fctx m c p = maybe_display_error com fctx (Printf.sprintf "Invalid modifier: %s is only supported %s" m c) p + let invalid_modifier_on_property com fctx m p = + maybe_display_error com fctx (Printf.sprintf "Invalid modifier: %s is not supported on properties" m) p + let missing_expression com fctx reason p = maybe_display_error com fctx (Printf.sprintf "%s" reason) p @@ -1613,6 +1616,7 @@ let init_field (ctx,cctx,fctx) f = if not (has_class_flag c CExtern) && not (Meta.has Meta.Native f.cff_meta) then Typecore.check_field_name ctx name p; List.iter (fun acc -> match (fst acc, f.cff_kind) with + | AFinal, FProp _ when not (has_class_flag c CExtern) && ctx.com.platform <> Java -> invalid_modifier_on_property ctx.com fctx (Ast.s_placed_access acc) (snd acc) | APublic, _ | APrivate, _ | AStatic, _ | AFinal, _ | AExtern, _ -> () | ADynamic, FFun _ | AOverride, FFun _ | AMacro, FFun _ | AInline, FFun _ | AInline, FVar _ | AAbstract, FFun _ | AOverload, FFun _ -> () | AEnum, (FVar _ | FProp _) -> () diff --git a/src/typing/typeloadParse.ml b/src/typing/typeloadParse.ml index 86595e5edff..b947479ade4 100644 --- a/src/typing/typeloadParse.ml +++ b/src/typing/typeloadParse.ml @@ -102,7 +102,7 @@ let resolve_module_file com m remap p = with Not_found -> Common.find_file com (compose_path true) in - let file = (match String.lowercase (snd m) with + let file = (match ExtString.String.lowercase (snd m) with | "con" | "aux" | "prn" | "nul" | "com1" | "com2" | "com3" | "lpt1" | "lpt2" | "lpt3" when Sys.os_type = "Win32" -> (* these names are reserved by the OS - old DOS legacy, such files cannot be easily created but are reported as visible *) if (try (Unix.stat file).Unix.st_size with _ -> 0) > 0 then file else raise Not_found diff --git a/src/typing/typer.ml b/src/typing/typer.ml index 8fca98a9a6a..f542570e406 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -402,8 +402,9 @@ let rec type_ident_raise ctx i p mode with_type = let t = match with_type with | WithType.WithType(t,_) -> begin match follow t with - | TMono r -> - (* If our expected type is a monomorph, bind it to Null. *) + | TMono r when not (is_nullable t) -> + (* If our expected type is a monomorph, bind it to Null. The is_nullable check is here because + the expected type could already be Null, in which case we don't want to double-wrap (issue #11286). *) Monomorph.do_bind r (tnull()) | _ -> (* Otherwise there's no need to create a monomorph, we can just type the null literal @@ -1691,7 +1692,7 @@ and type_meta ?(mode=MGet) ctx m e1 with_type p = | _ -> e() end | (Meta.StoredTypedExpr,_,_) -> - MacroContext.type_stored_expr ctx e1 + type_stored_expr ctx e1 | (Meta.NoPrivateAccess,_,_) -> ctx.meta <- List.filter (fun(m,_,_) -> m <> Meta.PrivateAccess) ctx.meta; e() @@ -1723,6 +1724,9 @@ and type_meta ?(mode=MGet) ctx m e1 with_type p = | (EReturn e, p) -> type_return ~implicit:true ctx e with_type p | _ -> e() end + (* Allow `${...}` reification because it's a noop and happens easily with macros *) + | (Meta.Dollar "",_,p) -> + e() | (Meta.Dollar s,_,p) -> display_error ctx.com (Printf.sprintf "Reification $%s is not allowed outside of `macro` expression" s) p; e() diff --git a/src/typing/typerBase.ml b/src/typing/typerBase.ml index 92ddd947c18..f43c1df0d01 100644 --- a/src/typing/typerBase.ml +++ b/src/typing/typerBase.ml @@ -173,6 +173,14 @@ let get_this ctx p = | FunConstructor | FunMember -> mk (TConst TThis) ctx.tthis p +let get_stored_typed_expr ctx id = + let e = ctx.com.stored_typed_exprs#find id in + Texpr.duplicate_tvars (fun e -> get_this ctx e.epos) e + +let type_stored_expr ctx e1 = + let id = match e1 with (EConst (Int (s, _)),_) -> int_of_string s | _ -> die "" __LOC__ in + get_stored_typed_expr ctx id + let assign_to_this_is_allowed ctx = match ctx.curclass.cl_kind with | KAbstractImpl _ -> diff --git a/src/typing/typerDisplay.ml b/src/typing/typerDisplay.ml index 26d176ad2a9..ba39482a18a 100644 --- a/src/typing/typerDisplay.ml +++ b/src/typing/typerDisplay.ml @@ -346,20 +346,26 @@ and display_expr ctx e_ast e dk mode with_type p = let fa = get_constructor_access c params p in fa.fa_field,c in - let maybe_expand_overload e e_on host cf = match mode with + let maybe_expand_overload el_typed e e_on host cf = match mode with | MCall el when cf.cf_overloads <> [] -> let fa = FieldAccess.create e_on cf host false p in - let fcc = unify_field_call ctx fa [] el p false in + let fcc = unify_field_call ctx fa el_typed el p false in FieldAccess.get_field_expr {fa with fa_field = fcc.fc_field} FCall | _ -> e in + let e,el_typed = match e.eexpr with + | TMeta((Meta.StaticExtension,[e_self],_),e1) -> + e1,[type_stored_expr ctx e_self] + | _ -> + e,[] + in (* If we display on a TField node that points to an overloaded field, let's try to unify the field call in order to resolve the correct overload (issue #7753). *) let e = match e.eexpr with - | TField(e1,FStatic(c,cf)) -> maybe_expand_overload e e1 (FHStatic c) cf - | TField(e1,(FInstance(c,tl,cf) | FClosure(Some(c,tl),cf))) -> maybe_expand_overload e e1 (FHInstance(c,tl)) cf - | TField(e1,(FAnon cf | FClosure(None,cf))) -> maybe_expand_overload e e1 FHAnon cf + | TField(e1,FStatic(c,cf)) -> maybe_expand_overload el_typed e e1 (FHStatic c) cf + | TField(e1,(FInstance(c,tl,cf) | FClosure(Some(c,tl),cf))) -> maybe_expand_overload el_typed e e1 (FHInstance(c,tl)) cf + | TField(e1,(FAnon cf | FClosure(None,cf))) -> maybe_expand_overload el_typed e e1 FHAnon cf | _ -> e in match ctx.com.display.dms_kind with diff --git a/std/haxe/macro/Printer.hx b/std/haxe/macro/Printer.hx index 6766acb3d0f..bf43c742be0 100644 --- a/std/haxe/macro/Printer.hx +++ b/std/haxe/macro/Printer.hx @@ -390,11 +390,13 @@ class Printer { var to = to == null ? [] : to.copy(); var isEnum = false; - for (flag in tflags) { - switch (flag) { - case AbEnum: isEnum = true; - case AbFrom(ct): from.push(ct); - case AbTo(ct): to.push(ct); + if (tflags != null) { + for (flag in tflags) { + switch (flag) { + case AbEnum: isEnum = true; + case AbFrom(ct): from.push(ct); + case AbTo(ct): to.push(ct); + } } } diff --git a/std/hl/CArray.hx b/std/hl/CArray.hx index 850d86f5705..81c7329e82b 100644 --- a/std/hl/CArray.hx +++ b/std/hl/CArray.hx @@ -9,9 +9,14 @@ abstract CArray(Abstract<"hl_carray">) { public var length(get,never) : Int; - inline function get_length() return getLen(cast this); + #if (hl_ver >= version("1.14.0")) + inline function get_length() return untyped $asize(this); + @:arrayAccess inline function get( index : Int ) : T return untyped this[index]; + #else + inline function get_length() return getLen(cast this); @:arrayAccess inline function get( index : Int ) : T return getIndex(cast this, index); + #end public static function alloc( cl : Class, size : Int ) : CArray { return cast alloc_carray( (cast cl:BaseType).__type__ , size ); diff --git a/tests/display/build.hxml b/tests/display/build.hxml index b751ec6b939..597bba6de78 100644 --- a/tests/display/build.hxml +++ b/tests/display/build.hxml @@ -5,4 +5,4 @@ -lib haxeserver --interp -D use-rtti-doc -#-D test=9133 \ No newline at end of file +#-D test=11285 \ No newline at end of file diff --git a/tests/display/src/cases/Issue11285.hx b/tests/display/src/cases/Issue11285.hx new file mode 100644 index 00000000000..b0735473e7c --- /dev/null +++ b/tests/display/src/cases/Issue11285.hx @@ -0,0 +1,34 @@ +package cases; + +class Issue11285 extends DisplayTestCase { + /** + using Issue11285.MathTools; + + function main() { + var float = 0.0; + var int = 0; + float.wrapA{-1-}round(0, 1); + int.wrap{-2-}Around(0, 1); + } + + class MathTools { + + extern overload public static inline function {-3-}wrapAround{-4-}(v:Int, min:Int, max:Int):Int { + var range = max - min; + return min + (((v - min) % range) + range) % range; + } + + extern overload public static inline function {-5-}wrapAround{-6-}(v:Float, min:Float, max:Float):Float { + var range = max - min; + return min + (((v - min) % range) + range) % range; + } + } + **/ + function test() { + eq(range(5, 6), position(pos(1))); + eq("(v : Float, min : Float, max : Float) -> Float", type(pos(1))); + + eq(range(3, 4), position(pos(2))); + eq("(v : Int, min : Int, max : Int) -> Int", type(pos(2))); + } +} diff --git a/tests/misc/Issue11280/Main.hx b/tests/misc/Issue11280/Main.hx new file mode 100644 index 00000000000..12956fb10ce --- /dev/null +++ b/tests/misc/Issue11280/Main.hx @@ -0,0 +1,3 @@ +function main() { + var foo(get, never):Int; +} diff --git a/tests/misc/Issue11280/Main2.hx b/tests/misc/Issue11280/Main2.hx new file mode 100644 index 00000000000..25d736e7198 --- /dev/null +++ b/tests/misc/Issue11280/Main2.hx @@ -0,0 +1,6 @@ +class Main { + public final bar(get, never):Int; + function get_bar():Int return 42; + + static function main() {} +} diff --git a/tests/misc/Issue11280/compile-fail.hxml b/tests/misc/Issue11280/compile-fail.hxml new file mode 100644 index 00000000000..b66ea29f280 --- /dev/null +++ b/tests/misc/Issue11280/compile-fail.hxml @@ -0,0 +1,3 @@ +-main Main +-D message.reporting=pretty +-D message.no-color diff --git a/tests/misc/Issue11280/compile-fail.hxml.stderr b/tests/misc/Issue11280/compile-fail.hxml.stderr new file mode 100644 index 00000000000..137f8c4265c --- /dev/null +++ b/tests/misc/Issue11280/compile-fail.hxml.stderr @@ -0,0 +1,6 @@ +[ERROR] Main.hx:2: characters 9-21 + + 2 | var foo(get, never):Int; + | ^^^^^^^^^^^^ + | Cannot define property accessors for local vars + diff --git a/tests/misc/Issue11280/compile2-fail.hxml b/tests/misc/Issue11280/compile2-fail.hxml new file mode 100644 index 00000000000..04c12f8cb8b --- /dev/null +++ b/tests/misc/Issue11280/compile2-fail.hxml @@ -0,0 +1,3 @@ +-main Main2 +-D message.reporting=pretty +-D message.no-color diff --git a/tests/misc/Issue11280/compile2-fail.hxml.stderr b/tests/misc/Issue11280/compile2-fail.hxml.stderr new file mode 100644 index 00000000000..01a86928c3a --- /dev/null +++ b/tests/misc/Issue11280/compile2-fail.hxml.stderr @@ -0,0 +1,6 @@ +[ERROR] Main2.hx:2: characters 9-14 + + 2 | public final bar(get, never):Int; + | ^^^^^ + | Invalid modifier: final is not supported on properties + diff --git a/tests/misc/hl/projects/Issue11293/Main.hx b/tests/misc/hl/projects/Issue11293/Main.hx new file mode 100644 index 00000000000..a3d36a7c3c7 --- /dev/null +++ b/tests/misc/hl/projects/Issue11293/Main.hx @@ -0,0 +1,14 @@ +class Main { + static function main() { + var a = new TShaderConstant(true); + trace(a.bool); + } +} + +class TShaderConstant { + public var bool: Bool; + + public function new(boolValue: Bool) { + this.bool = boolValue; + } +} diff --git a/tests/misc/hl/projects/Issue11293/compile.hxml b/tests/misc/hl/projects/Issue11293/compile.hxml new file mode 100644 index 00000000000..72f603b5157 --- /dev/null +++ b/tests/misc/hl/projects/Issue11293/compile.hxml @@ -0,0 +1,2 @@ +--main Main +--hl out/main.c diff --git a/tests/misc/projects/Issue11193/Macro.hx b/tests/misc/projects/Issue11193/Macro.hx new file mode 100644 index 00000000000..d2ed9e0f66c --- /dev/null +++ b/tests/misc/projects/Issue11193/Macro.hx @@ -0,0 +1,6 @@ +class Macro { + static function test() { + static var m:Map = []; + trace(m); + } +} diff --git a/tests/misc/projects/Issue11193/compile.hxml b/tests/misc/projects/Issue11193/compile.hxml new file mode 100644 index 00000000000..660593079f7 --- /dev/null +++ b/tests/misc/projects/Issue11193/compile.hxml @@ -0,0 +1 @@ +--macro Macro.test() diff --git a/tests/misc/projects/Issue11286/Main.hx b/tests/misc/projects/Issue11286/Main.hx new file mode 100644 index 00000000000..fb474cfdc19 --- /dev/null +++ b/tests/misc/projects/Issue11286/Main.hx @@ -0,0 +1,14 @@ +function main() { + var a = null; + if (a == null) a = 10; + $type(a); // Null> + + var b = null; + $type(b); // Null> + b = null; + $type(b); // Null>> + b = null; + $type(b); // Null>>> + b = 10; + $type(b); // Null>> +} \ No newline at end of file diff --git a/tests/misc/projects/Issue11286/compile.hxml b/tests/misc/projects/Issue11286/compile.hxml new file mode 100644 index 00000000000..fab0aeecc3d --- /dev/null +++ b/tests/misc/projects/Issue11286/compile.hxml @@ -0,0 +1 @@ +--main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue11286/compile.hxml.stderr b/tests/misc/projects/Issue11286/compile.hxml.stderr new file mode 100644 index 00000000000..b7a89f0e169 --- /dev/null +++ b/tests/misc/projects/Issue11286/compile.hxml.stderr @@ -0,0 +1,5 @@ +Main.hx:4: characters 8-9 : Warning : Null +Main.hx:7: characters 8-9 : Warning : Null> +Main.hx:9: characters 8-9 : Warning : Null> +Main.hx:11: characters 8-9 : Warning : Null> +Main.hx:13: characters 8-9 : Warning : Null \ No newline at end of file diff --git a/tests/runci/targets/Hl.hx b/tests/runci/targets/Hl.hx index 0dd267a6e4c..cc01ac2dd08 100644 --- a/tests/runci/targets/Hl.hx +++ b/tests/runci/targets/Hl.hx @@ -73,6 +73,7 @@ class Hl { getHlDependencies(); runCommand("haxe", ["compile-hl.hxml"].concat(args)); + runCommand("haxe", ["compile-hlc.hxml"].concat(args)); runCommand(hlBinary, ["bin/unit.hl"]); changeDirectory(threadsDir); diff --git a/tests/unit/compile-hlc.hxml b/tests/unit/compile-hlc.hxml new file mode 100644 index 00000000000..46a19098ca4 --- /dev/null +++ b/tests/unit/compile-hlc.hxml @@ -0,0 +1,5 @@ +compile-each.hxml +--main unit.TestMain +-hl bin/hlc/main.c +-D hl-check +-D hl-ver=1.13.0 diff --git a/tests/unit/compile.hxml b/tests/unit/compile.hxml index 2c5775cb359..333e94fec17 100644 --- a/tests/unit/compile.hxml +++ b/tests/unit/compile.hxml @@ -14,6 +14,7 @@ compile-java-runner.hxml --next compile-flash.hxml --next compile-js.hxml --next compile-hl.hxml +--next compile-hlc.hxml --next compile-lua.hxml --next compile-neko.hxml --next compile-php.hxml diff --git a/tests/unit/src/unit/issues/Issue11212.hx b/tests/unit/src/unit/issues/Issue11212.hx new file mode 100644 index 00000000000..7a81c2eb95f --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11212.hx @@ -0,0 +1,19 @@ +package unit.issues; + +class Issue11212 extends Test { + var value = 123; + + function test() { + #if !macro + var foo:Foo = value; // on JS this generates `let foo = function() { return this.value; };` on JS + eq(123, foo()); + #end + } +} + +@:callable +private abstract Foo(() -> Int) from () -> Int { + @:from macro static function ofExpr(e) { + return macro @:pos(e.pos) (function():Int return $e : Foo); + } +} diff --git a/tests/unit/src/unit/issues/Issue11317.hx b/tests/unit/src/unit/issues/Issue11317.hx new file mode 100644 index 00000000000..73b6974fa09 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11317.hx @@ -0,0 +1,10 @@ +package unit.issues; + +class Issue11317 extends Test { + function test() { + var array:Array = ["0", "1", "2", "3", "4"]; + array.resize(0); + array.resize(5); + utest.Assert.same([null, null, null, null, null], array); + } +}