From 92c197b85f140fe45c8f3b63f9cf773aa99def4d Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 23 Nov 2023 08:58:56 +0100 Subject: [PATCH 001/184] [hl/c] fix reserved keywords (#11408) * [tests] update test for 11378 * [hlc] fix reserved keywords --- src/generators/hl2c.ml | 4 ++-- tests/misc/hl/reservedKeywords/Macro.macro.hx | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/generators/hl2c.ml b/src/generators/hl2c.ml index e835f73303f..ac567ed88ef 100644 --- a/src/generators/hl2c.ml +++ b/src/generators/hl2c.ml @@ -98,13 +98,13 @@ let keywords = "typeof"; (* C11 *) "_Alignas";"_Alignof";"_Atomic";"_Bool";"_Complex";"_Generic";"_Imaginary";"_Noreturn";"_Static_assert";"_Thread_local";"_Pragma"; - "inline";"restrict" + "inline";"restrict";"_restrict" ] in let h = Hashtbl.create 0 in List.iter (fun i -> Hashtbl.add h i ()) c_kwds; h -let ident i = if (Hashtbl.mem keywords i) || (ExtString.String.starts_with "__" i) then "_hx_" ^ i else i +let ident i = if (Hashtbl.mem keywords i) || (ExtString.String.starts_with i "__") then "_hx_" ^ i else i let s_comp = function | CLt -> "<" diff --git a/tests/misc/hl/reservedKeywords/Macro.macro.hx b/tests/misc/hl/reservedKeywords/Macro.macro.hx index a47548b6cea..9e76e54d2eb 100644 --- a/tests/misc/hl/reservedKeywords/Macro.macro.hx +++ b/tests/misc/hl/reservedKeywords/Macro.macro.hx @@ -19,12 +19,12 @@ class Macro { "typeof", // C11 "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local", "_Pragma", - "inline", "restrict" + "inline", "restrict", "_restrict" ]; var pos = Context.currentPos(); - for (k in keywords) + for (k in keywords) { fields.push({ pos: pos, name: "_test_" + k, @@ -32,6 +32,14 @@ class Macro { kind: FVar(macro :String, null) }); + fields.push({ + pos: pos, + name: "_test2_" + k, + meta: [{pos: pos, name: ":native", params: [macro $v{'__' + k}]}], + kind: FVar(macro :String, null) + }); + } + return fields; } } From 16d4f1fe3a4ab4dc4db50881dedc99718a4bed66 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Fri, 24 Nov 2023 11:26:18 +0100 Subject: [PATCH 002/184] [macro] don't exception-wrap every API function (#11374) --- src/macro/eval/evalMain.ml | 15 ++------------- src/macro/macroApi.ml | 30 ++++++++++++++++++++++-------- src/typing/macroContext.ml | 8 +++++++- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/macro/eval/evalMain.ml b/src/macro/eval/evalMain.ml index efe3e35d788..20db1dbf6d3 100644 --- a/src/macro/eval/evalMain.ml +++ b/src/macro/eval/evalMain.ml @@ -376,19 +376,8 @@ let init ctx = () let setup get_api = let api = get_api (fun() -> (get_ctx()).curapi.get_com()) (fun() -> (get_ctx()).curapi) in - List.iter (fun (n,v) -> match v with - | VFunction(f,b) -> - let f vl = try - f vl - with - | Sys_error msg | Failure msg | Invalid_argument msg -> - exc_string msg - | MacroApi.Invalid_expr -> - exc_string "Invalid expression" - in - let v = VFunction (f,b) in - Hashtbl.replace GlobalState.macro_lib n v - | _ -> die "" __LOC__ + List.iter (fun (n,v) -> + Hashtbl.replace GlobalState.macro_lib n v ) api; Globals.macro_platform := Globals.Eval diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index 8b0a09a0467..78cb4d4286e 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -70,6 +70,7 @@ type 'value compiler_api = { display_error : ?depth:int -> (string -> pos -> unit); with_imports : 'a . import list -> placed_name list list -> (unit -> 'a) -> 'a; with_options : 'a . compiler_options -> (unit -> 'a) -> 'a; + exc_string : 'a . string -> 'a; } @@ -1013,12 +1014,9 @@ let encode_meta m set = encode_meta_content (!meta) ); "add", vfun3 (fun k vl p -> - (try - let el = List.map decode_expr (decode_array vl) in - meta := (Meta.from_string (decode_string k), el, decode_pos p) :: !meta; - set (!meta) - with Invalid_expr -> - failwith "Invalid expression"); + let el = List.map decode_expr (decode_array vl) in + meta := (Meta.from_string (decode_string k), el, decode_pos p) :: !meta; + set (!meta); vnull ); "extract", vfun1 (fun k -> @@ -1799,6 +1797,19 @@ let rec make_const e = **) let macro_api ccom get_api = + let decode_type v = + try decode_type v + with Invalid_expr -> (get_api()).exc_string "Invalid expression" + in + let decode_expr v = + try decode_expr v + with Invalid_expr -> (get_api()).exc_string "Invalid expression" + in + let decode_texpr v = + try decode_texpr v + with Invalid_expr -> (get_api()).exc_string "Invalid expression" + in + let failwith s = (get_api()).exc_string s in [ "contains_display_position", vfun1 (fun p -> let p = decode_pos p in @@ -1929,14 +1940,17 @@ let macro_api ccom get_api = ); "do_parse", vfun3 (fun s p b -> let s = decode_string s in - if s = "" then raise Invalid_expr; + if s = "" then (get_api()).exc_string "Invalid expression"; encode_expr ((get_api()).parse_string s (decode_pos p) (decode_bool b)) ); "make_expr", vfun2 (fun v p -> encode_expr (value_to_expr v (decode_pos p)) ); "signature", vfun1 (fun v -> - encode_string (Digest.to_hex (value_signature v)) + try + encode_string (Digest.to_hex (value_signature v)) + with Invalid_argument msg -> + (get_api()).exc_string msg ); "to_complex_type", vfun1 (fun v -> try encode_ctype (TExprToExpr.convert_type' (decode_type v)) diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index e812e608f8d..be211c9f133 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -197,7 +197,8 @@ let make_macro_com_api com mcom p = let r = match ParserEntry.parse_expr_string com.defines s p raise_typing_error inl with | ParseSuccess(data,true,_) when inl -> data (* ignore errors when inline-parsing in display file *) | ParseSuccess(data,_,_) -> data - | ParseError _ -> raise MacroApi.Invalid_expr in + | ParseError _ -> Interp.exc_string "Invalid expression" + in exit(); r with Error err -> @@ -315,6 +316,7 @@ let make_macro_com_api com mcom p = warning = (fun ?(depth=0) w msg p -> com.warning ~depth w [] msg p ); + exc_string = Interp.exc_string; } let make_macro_api ctx mctx p = @@ -327,6 +329,10 @@ let make_macro_api ctx mctx p = raise_typing_error "Malformed metadata string" p in let com_api = make_macro_com_api ctx.com mctx.com p in + let mk_type_path ?sub path = + try mk_type_path ?sub path + with Invalid_argument s -> com_api.exc_string s + in { com_api with MacroApi.get_type = (fun s -> From 5d1f27460057670a1a7bade26dd3a6a566daf8f7 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Fri, 24 Nov 2023 20:31:01 +0100 Subject: [PATCH 003/184] [tests] make display tests much faster --- tests/display/src/Main.hx | 2 +- tests/display/src/cases/{Type.hx => NotType.hx} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/display/src/cases/{Type.hx => NotType.hx} (74%) diff --git a/tests/display/src/Main.hx b/tests/display/src/Main.hx index bb16daa11d8..3ad65be92c2 100644 --- a/tests/display/src/Main.hx +++ b/tests/display/src/Main.hx @@ -12,7 +12,7 @@ class Main { report.displaySuccessResults = NeverShowSuccessResults; var haxeServer = @:privateAccess DisplayTestContext.haxeServer; - haxeServer.setDefaultRequestArguments(["-cp", "src", "-cp", "src-shared", "--no-output", "-lib", "utest"]); + haxeServer.setDefaultRequestArguments(["-cp", "src", "-cp", "src-shared", "--no-output"]); DisplayTestContext.runHaxe([]); runner.run(); haxeServer.close(); diff --git a/tests/display/src/cases/Type.hx b/tests/display/src/cases/NotType.hx similarity index 74% rename from tests/display/src/cases/Type.hx rename to tests/display/src/cases/NotType.hx index 6f029965cbc..ae05c866ee3 100644 --- a/tests/display/src/cases/Type.hx +++ b/tests/display/src/cases/NotType.hx @@ -1,6 +1,6 @@ package cases; -class Type extends DisplayTestCase { +class NotType extends DisplayTestCase { /** abstract {-1-}A(Int) {} **/ From a270435a45eda3de485f7adf68d3d49d625b6d1c Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Sat, 25 Nov 2023 16:33:35 +0100 Subject: [PATCH 004/184] [display] diagnostics as json rpc (#11412) * [diagnostics] implement diagnostics as json rpc * [tests] use json rpc diagnostics * [tests] add tests for json rpc diagnostics * [diagnostics] no need for its own exception * [compiler] fix run_or_diagnose weird edge case * [diagnostics] no need for after_compilation callback anymore --- src/compiler/compiler.ml | 26 +++++--- src/compiler/displayOutput.ml | 12 +++- src/compiler/displayProcessing.ml | 6 +- src/compiler/server.ml | 21 ++++--- src/context/common.ml | 5 +- src/context/display/diagnosticsPrinter.ml | 5 +- src/context/display/displayJson.ml | 49 +++++++++++++++ src/core/display/displayPosition.ml | 19 +++++- src/typing/typeloadParse.ml | 32 ++++++---- std/haxe/display/Display.hx | 17 +++++ tests/server/src/TestCase.hx | 31 +++++---- tests/server/src/cases/ServerTests.hx | 63 +++++++++++++++++-- .../src/cases/display/issues/Issue10635.hx | 22 ++++--- .../src/cases/display/issues/Issue8687.hx | 9 +-- .../src/cases/display/issues/Issue9705.hx | 12 ++-- tests/server/src/cases/issues/Issue10653.hx | 9 ++- tests/server/src/cases/issues/Issue11177.hx | 18 ++++-- tests/server/src/cases/issues/Issue11184.hx | 14 +++-- tests/server/src/cases/issues/Issue11203.hx | 14 ++--- .../test/templates/issues/Issue9134/Main.hx | 5 ++ .../test/templates/issues/Issue9134/Main2.hx | 6 ++ .../test/templates/issues/Issue9134/Other.hx | 2 + .../test/templates/issues/Issue9134/Other2.hx | 6 ++ 23 files changed, 307 insertions(+), 96 deletions(-) create mode 100644 tests/server/test/templates/issues/Issue9134/Main.hx create mode 100644 tests/server/test/templates/issues/Issue9134/Main2.hx create mode 100644 tests/server/test/templates/issues/Issue9134/Other.hx create mode 100644 tests/server/test/templates/issues/Issue9134/Other2.hx diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index c6194c734f1..b38404939ab 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -2,29 +2,35 @@ open Globals open Common open CompilationContext -let run_or_diagnose ctx f arg = +let run_or_diagnose ctx f = let com = ctx.com in - let handle_diagnostics ?(depth = 0) msg p kind = + let handle_diagnostics msg p kind = ctx.has_error <- true; - add_diagnostics_message ~depth com msg p kind Error; - DisplayOutput.emit_diagnostics ctx.com + add_diagnostics_message com msg p kind Error; + match com.report_mode with + | RMLegacyDiagnostics _ -> DisplayOutput.emit_legacy_diagnostics ctx.com + | RMDiagnostics _ -> DisplayOutput.emit_diagnostics ctx.com + | _ -> die "" __LOC__ in if is_diagnostics com then begin try - f arg + f () with | Error.Error err -> ctx.has_error <- true; Error.recurse_error (fun depth err -> add_diagnostics_message ~depth com (Error.error_msg err.err_message) err.err_pos DKCompilerMessage Error ) err; - DisplayOutput.emit_diagnostics ctx.com + (match com.report_mode with + | RMLegacyDiagnostics _ -> DisplayOutput.emit_legacy_diagnostics ctx.com + | RMDiagnostics _ -> DisplayOutput.emit_diagnostics ctx.com + | _ -> die "" __LOC__) | Parser.Error(msg,p) -> handle_diagnostics (Parser.error_msg msg) p DKParserError | Lexer.Error(msg,p) -> handle_diagnostics (Lexer.error_msg msg) p DKParserError end else - f arg + f () let run_command ctx cmd = let t = Timer.timer ["command";cmd] in @@ -297,7 +303,7 @@ let do_type ctx mctx actx display_file_dot_path macro_cache_enabled = if com.display.dms_kind <> DMNone then DisplayTexpr.check_display_file tctx cs; List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath null_pos)) (List.rev actx.classes); Finalization.finalize tctx; - ) (); + ); end with TypeloadParse.DisplayInMacroBlock -> ignore(DisplayProcessing.load_display_module_in_macro tctx display_file_dot_path true) ); @@ -317,7 +323,7 @@ let finalize_typing ctx tctx = let com = ctx.com in enter_stage com CFilteringStart; ServerMessage.compiler_stage com; - let main, types, modules = run_or_diagnose ctx Finalization.generate tctx in + let main, types, modules = run_or_diagnose ctx (fun () -> Finalization.generate tctx) in com.main <- main; com.types <- types; com.modules <- modules; @@ -326,7 +332,7 @@ let finalize_typing ctx tctx = let filter ctx tctx before_destruction = let t = Timer.timer ["filters"] in DeprecationCheck.run ctx.com; - run_or_diagnose ctx Filters.run tctx ctx.com.main before_destruction; + run_or_diagnose ctx (fun () -> Filters.run tctx ctx.com.main before_destruction); t() let compile ctx actx callbacks = diff --git a/src/compiler/displayOutput.ml b/src/compiler/displayOutput.ml index 2e1f0f7b389..c1ddb3bf4d0 100644 --- a/src/compiler/displayOutput.ml +++ b/src/compiler/displayOutput.ml @@ -368,12 +368,22 @@ let handle_type_path_exception ctx p c is_import pos = api.send_result (DisplayException.fields_to_json ctx fields kind (DisplayTypes.make_subject None pos)); end -let emit_diagnostics com = +let emit_legacy_diagnostics com = let dctx = Diagnostics.run com in let s = Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics com dctx) in DisplayPosition.display_position#reset; raise (Completion s) +let emit_diagnostics com = + (match com.Common.json_out with + | None -> die "" __LOC__ + | Some api -> + let dctx = Diagnostics.run com in + let diagnostics = DiagnosticsPrinter.json_of_diagnostics com dctx in + DisplayPosition.display_position#reset; + api.send_result diagnostics; + raise Abort (* not reached because send_result always raises *)) + let emit_statistics tctx = let stats = Statistics.collect_statistics tctx [SFFile (DisplayPosition.display_position#get).pfile] true in let s = Statistics.Printer.print_statistics stats in diff --git a/src/compiler/displayProcessing.ml b/src/compiler/displayProcessing.ml index ebdf508b9f0..580a9d708a1 100644 --- a/src/compiler/displayProcessing.ml +++ b/src/compiler/displayProcessing.ml @@ -22,7 +22,7 @@ let handle_display_argument_old com file_pos actx = actx.did_something <- true; (try Memory.display_memory com with e -> prerr_endline (Printexc.get_backtrace ())); | "diagnostics" -> - com.report_mode <- RMDiagnostics [] + com.report_mode <- RMLegacyDiagnostics [] | _ -> let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format: " ^ file_pos) in let file = Helper.unquote file in @@ -46,7 +46,7 @@ let handle_display_argument_old com file_pos actx = | "module-symbols" -> create (DMModuleSymbols None) | "diagnostics" -> - com.report_mode <- RMDiagnostics [file_unique]; + com.report_mode <- RMLegacyDiagnostics [file_unique]; let dm = create DMNone in {dm with dms_display_file_policy = DFPAlso; dms_per_file = true; dms_populate_cache = !ServerConfig.populate_cache_from_display} | "statistics" -> @@ -348,6 +348,8 @@ let handle_display_after_finalization ctx tctx display_file_dot_path = end; process_global_display_mode com tctx; begin match com.report_mode with + | RMLegacyDiagnostics _ -> + DisplayOutput.emit_legacy_diagnostics com | RMDiagnostics _ -> DisplayOutput.emit_diagnostics com | RMStatistics -> diff --git a/src/compiler/server.ml b/src/compiler/server.ml index f3bcf3a6e0e..07c4257787e 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -16,15 +16,7 @@ let has_error ctx = ctx.has_error || ctx.com.Common.has_error let check_display_flush ctx f_otherwise = match ctx.com.json_out with - | None -> - if is_diagnostics ctx.com then begin - List.iter (fun cm -> - add_diagnostics_message ~depth:cm.cm_depth ctx.com cm.cm_message cm.cm_pos cm.cm_kind cm.cm_severity - ) (List.rev ctx.messages); - raise (Completion (Diagnostics.print ctx.com)) - end else - f_otherwise () - | Some api -> + | Some api when not (is_diagnostics ctx.com) -> if has_error ctx then begin let errors = List.map (fun cm -> JObject [ @@ -35,6 +27,17 @@ let check_display_flush ctx f_otherwise = match ctx.com.json_out with ) (List.rev ctx.messages) in api.send_error errors end + | _ -> + if is_diagnostics ctx.com then begin + List.iter (fun cm -> + add_diagnostics_message ~depth:cm.cm_depth ctx.com cm.cm_message cm.cm_pos cm.cm_kind cm.cm_severity + ) (List.rev ctx.messages); + (match ctx.com.report_mode with + | RMDiagnostics _ -> () + | RMLegacyDiagnostics _ -> raise (Completion (Diagnostics.print ctx.com)) + | _ -> die "" __LOC__) + end else + f_otherwise () let current_stdin = ref None diff --git a/src/context/common.ml b/src/context/common.ml index 76245ae0c1b..745b85cbbeb 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -289,7 +289,8 @@ let s_compiler_stage = function type report_mode = | RMNone - | RMDiagnostics of Path.UniqueKey.t list + | RMLegacyDiagnostics of (Path.UniqueKey.t list) + | RMDiagnostics of (Path.UniqueKey.t * string option (* file contents *)) list | RMStatistics class virtual ['key,'value] lookup = object(self) @@ -890,7 +891,7 @@ let create compilation_step cs version args = com let is_diagnostics com = match com.report_mode with - | RMDiagnostics _ -> true + | RMLegacyDiagnostics _ | RMDiagnostics _ -> true | _ -> false let disable_report_mode com = diff --git a/src/context/display/diagnosticsPrinter.ml b/src/context/display/diagnosticsPrinter.ml index 82bb755366c..482fe05f48d 100644 --- a/src/context/display/diagnosticsPrinter.ml +++ b/src/context/display/diagnosticsPrinter.ml @@ -26,8 +26,9 @@ let make_diagnostic kd p sev code args = { let is_diagnostics_file com file_key = match com.report_mode with - | RMDiagnostics [] -> true - | RMDiagnostics file_keys -> List.exists (fun key' -> file_key = key') file_keys + | RMLegacyDiagnostics [] | RMDiagnostics [] -> true + | RMLegacyDiagnostics file_keys -> List.exists (fun key' -> file_key = key') file_keys + | RMDiagnostics file_keys -> List.exists (fun (key',_) -> file_key = key') file_keys | _ -> false module UnresolvedIdentifierSuggestion = struct diff --git a/src/context/display/displayJson.ml b/src/context/display/displayJson.ml index d120777475b..2ce233bb8a9 100644 --- a/src/context/display/displayJson.ml +++ b/src/context/display/displayJson.ml @@ -125,6 +125,55 @@ let handler = hctx.display#set_display_file false true; hctx.display#enable_display DMDefinition; ); + "display/diagnostics", (fun hctx -> + hctx.display#enable_display DMNone; + + let file = hctx.jsonrpc#get_opt_param (fun () -> + let file = hctx.jsonrpc#get_string_param "file" in + Path.get_full_path file + ) file_input_marker in + + if file <> file_input_marker then begin + let file_unique = hctx.com.file_keys#get file in + + let contents = hctx.jsonrpc#get_opt_param (fun () -> + let s = hctx.jsonrpc#get_string_param "contents" in + Some s + ) None in + + DisplayPosition.display_position#set { + pfile = file; + pmin = -1; + pmax = -1; + }; + + hctx.com.report_mode <- RMDiagnostics [file_unique, contents]; + hctx.com.display <- { hctx.com.display with dms_display_file_policy = DFPAlso; dms_per_file = true; dms_populate_cache = !ServerConfig.populate_cache_from_display}; + end else begin + let file_contents = hctx.jsonrpc#get_opt_param (fun () -> + hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_array_param "fileContents") [] + ) [] in + + if (List.length file_contents) = 0 then begin + hctx.com.report_mode <- RMDiagnostics [] + end else + let file_contents = List.map (fun fc -> match fc with + | JObject fl -> + let file = hctx.jsonrpc#get_string_field "fileContents" "file" fl in + let file = Path.get_full_path file in + let file_unique = hctx.com.file_keys#get file in + let contents = hctx.jsonrpc#get_opt_param (fun () -> + let s = hctx.jsonrpc#get_string_field "fileContents" "contents" fl in + Some s + ) None in + (file_unique, contents) + | _ -> invalid_arg "fileContents" + ) file_contents in + + DisplayPosition.display_position#set_files (List.map (fun (k, _) -> k) file_contents); + hctx.com.report_mode <- RMDiagnostics file_contents + end + ); "display/implementation", (fun hctx -> hctx.display#set_display_file false true; hctx.display#enable_display (DMImplementation); diff --git a/src/core/display/displayPosition.ml b/src/core/display/displayPosition.ml index a831d727036..1954b98ef67 100644 --- a/src/core/display/displayPosition.ml +++ b/src/core/display/displayPosition.ml @@ -11,6 +11,7 @@ class display_position_container = (** Current display position *) val mutable pos = null_pos val mutable file_key = None + val mutable file_keys = [] (** Display position value which was set with the latest `display_position#set p` call. Kept even after `display_position#reset` call. @@ -23,6 +24,10 @@ class display_position_container = pos <- p; last_pos <- p; file_key <- None + + method set_files files = + file_keys <- files + (** Get current display position *) @@ -43,7 +48,8 @@ class display_position_container = *) method reset = pos <- null_pos; - file_key <- None + file_key <- None; + file_keys <- [] (** Check if `p` contains current display position *) @@ -53,8 +59,15 @@ class display_position_container = Check if a file with `file_key` contains current display position *) method is_in_file file_key = - pos.pfile <> "?" - && self#get_file_key = file_key + (pos.pfile <> "?" && self#get_file_key = file_key) || self#has_file file_key + + (** + This is a hack; currently used by Diagnostics.collect_diagnostics when sending multiple files + to run diagnostics on via json rpc + *) + method has_file file_key = + List.mem file_key file_keys + (** Cut `p` at the position of the latest `display_position#set pos` call. *) diff --git a/src/typing/typeloadParse.ml b/src/typing/typeloadParse.ml index a79cc091e34..208b3714fdd 100644 --- a/src/typing/typeloadParse.ml +++ b/src/typing/typeloadParse.ml @@ -61,20 +61,26 @@ let parse_file_from_string com file p string = let current_stdin = ref None (* TODO: we're supposed to clear this at some point *) let parse_file com file p = - let use_stdin = (Common.defined com Define.DisplayStdin) && DisplayPosition.display_position#is_in_file (com.file_keys#get file) in - if use_stdin then - let s = - match !current_stdin with - | Some s -> - s - | None -> - let s = Std.input_all stdin in - close_in stdin; - current_stdin := Some s; - s - in + let contents = match com.report_mode with + | RMDiagnostics files -> + (try List.assoc (com.file_keys#get file) files with Not_found -> None) + | _ when (Common.defined com Define.DisplayStdin) && DisplayPosition.display_position#is_in_file (com.file_keys#get file) -> + Some (match !current_stdin with + | Some s -> + s + | None -> + let s = Std.input_all stdin in + close_in stdin; + current_stdin := Some s; + s + ) + | _ -> None + in + + match contents with + | Some s -> parse_file_from_string com file p s - else + | _ -> let ch = try open_in_bin file with _ -> raise_typing_error ("Could not open " ^ file) p in Std.finally (fun() -> close_in ch) (parse_file_from_lexbuf com file p) (Sedlexing.Utf8.from_channel ch) diff --git a/std/haxe/display/Display.hx b/std/haxe/display/Display.hx index aac5724c846..e6e03498e85 100644 --- a/std/haxe/display/Display.hx +++ b/std/haxe/display/Display.hx @@ -25,6 +25,7 @@ package haxe.display; import haxe.display.JsonModuleTypes; import haxe.display.Position; import haxe.display.Protocol; +import haxe.ds.ReadOnlyArray; /** Methods of the JSON-RPC-based `--display` protocol in Haxe 4. @@ -32,6 +33,11 @@ import haxe.display.Protocol; **/ @:publicFields class DisplayMethods { + /** + TODO documentation + **/ + static inline var Diagnostics = new HaxeRequestMethod("display/diagnostics"); + /** The completion request is sent from the client to Haxe to request code completion. Haxe automatically determines the type of completion to use based on the passed position, see `CompletionResultKind`. @@ -438,6 +444,17 @@ typedef PatternCompletion = ToplevelCompletion & { var isOutermostPattern:Bool; } +typedef DiagnosticsParams = { + var ?file:FsPath; + var ?contents:String; + var ?fileContents:Array<{file:FsPath, ?contents:String}>; +} + +typedef DiagnosticsResult = Response>; +}>> + enum abstract CompletionModeKind(Int) { var Field:CompletionModeKind>; var StructureField; diff --git a/tests/server/src/TestCase.hx b/tests/server/src/TestCase.hx index 5f8e59319ff..b4954a08a83 100644 --- a/tests/server/src/TestCase.hx +++ b/tests/server/src/TestCase.hx @@ -79,22 +79,26 @@ class TestCase implements ITest { server.stop(); } + function handleResult(result) { + lastResult = result; + debugLastResult = { + hasError: lastResult.hasError, + prints: lastResult.prints, + stderr: lastResult.stderr, + stdout: lastResult.stdout + }; + sendLogMessage(result.stdout); + for (print in result.prints) { + var line = print.trim(); + messages.push('Haxe print: $line'); + } + } + function runHaxe(args:Array, done:() -> Void) { messages = []; errorMessages = []; server.rawRequest(args, null, function(result) { - lastResult = result; - debugLastResult = { - hasError: lastResult.hasError, - prints: lastResult.prints, - stderr: lastResult.stderr, - stdout: lastResult.stdout - } - sendLogMessage(result.stdout); - for (print in result.prints) { - var line = print.trim(); - messages.push('Haxe print: $line'); - } + handleResult(result); if (result.hasError) { sendErrorMessage(result.stderr); } @@ -112,7 +116,10 @@ class TestCase implements ITest { callback:TResponse->Void, done:() -> Void) { var methodArgs = {method: method, id: 1, params: methodArgs}; args = args.concat(['--display', Json.stringify(methodArgs)]); + messages = []; + errorMessages = []; server.rawRequest(args, null, function(result) { + handleResult(result); callback(Json.parse(result.stderr).result.result); done(); }, function(msg) { diff --git a/tests/server/src/cases/ServerTests.hx b/tests/server/src/cases/ServerTests.hx index d9215d53fe7..3dbe47d7f7e 100644 --- a/tests/server/src/cases/ServerTests.hx +++ b/tests/server/src/cases/ServerTests.hx @@ -97,7 +97,9 @@ class ServerTests extends TestCase { var args = ["-main", "BrokenSyntax.hx", "--interp", "--no-output"]; runHaxe(args); assertErrorMessage("Expected }"); - runHaxe(args.concat(["--display", "Empty.hx@0@diagnostics"])); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Empty.hx")}, res -> { + Assert.equals(0, res.length); + }); runHaxe(args); assertErrorMessage("Expected }"); } @@ -143,6 +145,53 @@ class ServerTests extends TestCase { assertSuccess(); } + function testDiagnosticsFileContents() { + vfs.putContent("Main.hx", getTemplate("issues/Issue9134/Main.hx")); + vfs.putContent("Other.hx", getTemplate("issues/Issue9134/Other.hx")); + var args = ["-main", "Main", "Other"]; + + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {fileContents: [ + {file: new FsPath("Other.hx")}, + {file: new FsPath("Main.hx")}, + ]}, res -> { + Assert.equals(1, res.length); + Assert.equals(1, res[0].diagnostics.length); + var arg = res[0].diagnostics[0].args; + Assert.equals("Unused variable", (cast arg).description); + Assert.stringContains("Main.hx", res[0].file.toString()); + }); + + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Other.hx")}); + + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {fileContents: [ + {file: new FsPath("Main.hx"), contents: getTemplate("issues/Issue9134/Main2.hx")}, + {file: new FsPath("Other.hx"), contents: getTemplate("issues/Issue9134/Other2.hx")} + ]}, res -> { + Assert.equals(1, res.length); + Assert.equals(1, res[0].diagnostics.length); + var arg = res[0].diagnostics[0].args; + Assert.equals("Unused variable", (cast arg).description); + Assert.stringContains("Other.hx", res[0].file.toString()); + }); + + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Other.hx")}); + + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {fileContents: [ + {file: new FsPath("Main.hx"), contents: getTemplate("issues/Issue9134/Main.hx")}, + {file: new FsPath("Other.hx"), contents: getTemplate("issues/Issue9134/Other2.hx")} + ]}, res -> { + Assert.equals(2, res.length); + + for (i in 0...2) { + Assert.equals(1, res[i].diagnostics.length); + var arg = res[i].diagnostics[0].args; + Assert.equals("Unused variable", (cast arg).description); + } + }); + } + function testDiagnosticsRecache() { vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); var args = ["--main", "HelloWorld", "--interp"]; @@ -152,7 +201,9 @@ class ServerTests extends TestCase { runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")}); runHaxe(args); assertSkipping("HelloWorld", Tainted("server/invalidate")); - runHaxe(args.concat(["--display", "HelloWorld.hx@0@diagnostics"])); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("HelloWorld.hx")}, res -> { + Assert.equals(0, res.length); + }); runHaxe(args); assertReuse("HelloWorld"); } @@ -160,7 +211,9 @@ class ServerTests extends TestCase { function testDiagnosticsRecache2() { vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); var args = ["--main", "HelloWorld", "--interp"]; - runHaxe(args.concat(["--display", "HelloWorld.hx@0@diagnostics"])); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("HelloWorld.hx")}, res -> { + Assert.equals(0, res.length); + }); runHaxe(args); assertReuse("HelloWorld"); } @@ -172,7 +225,9 @@ class ServerTests extends TestCase { runHaxe(args); assertReuse("HelloWorld"); runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")}); - runHaxe(args.concat(["--display", "HelloWorld.hx@0@diagnostics"])); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("HelloWorld.hx")}, res -> { + Assert.equals(0, res.length); + }); runHaxe(args.concat(["--display", "HelloWorld.hx@0@hover"])); assertReuse("HelloWorld"); } diff --git a/tests/server/src/cases/display/issues/Issue10635.hx b/tests/server/src/cases/display/issues/Issue10635.hx index 1cd612e897f..e3098be5ad7 100644 --- a/tests/server/src/cases/display/issues/Issue10635.hx +++ b/tests/server/src/cases/display/issues/Issue10635.hx @@ -14,12 +14,15 @@ class Issue10635 extends DisplayTestCase { } **/ function test(_) { - var args = ["-main", "Main", "--display", "Main.hx@0@diagnostics"]; + var args = ["-main", "Main"]; vfs.putContent("Something.hx", getTemplate("issues/Issue10635/Something.hx")); - runHaxe(args); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(0, res.length); + }); runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); - runHaxe(args); - Assert.isTrue(lastResult.stderr.length == 2); // dumb, but we don't have a proper diagnostics structure in these tests + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(0, res.length); + }); } /** @@ -32,12 +35,15 @@ class Issue10635 extends DisplayTestCase { } **/ function testGenericClassPerMethod(_) { - var args = ["-main", "Main", "--display", "Main.hx@0@diagnostics"]; + var args = ["-main", "Main"]; vfs.putContent("Something.hx", "@:genericClassPerMethod " + getTemplate("issues/Issue10635/Something.hx")); - runHaxe(args); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(0, res.length); + }); runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); - runHaxe(args); - Assert.isTrue(lastResult.stderr.length == 2); // dumb, but we don't have a proper diagnostics structure in these tests + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(0, res.length); + }); } function testGenericAddition(_) { diff --git a/tests/server/src/cases/display/issues/Issue8687.hx b/tests/server/src/cases/display/issues/Issue8687.hx index 9f2ae343fbc..6550a53abb0 100644 --- a/tests/server/src/cases/display/issues/Issue8687.hx +++ b/tests/server/src/cases/display/issues/Issue8687.hx @@ -4,9 +4,10 @@ class Issue8687 extends TestCase { function test(_) { vfs.putContent("Main.hx", getTemplate("issues/Issue8687/Main.hx")); var args = ["-main", "Main", "--interp"]; - runHaxe(args.concat(["--display", "Main.hx@0@diagnostics"])); - - var diag = parseDiagnostics(); - Assert.equals("Invalid version string \"foo\". Should follow SemVer.", diag[0].args); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(1, res.length); + Assert.equals(1, res[0].diagnostics.length); + Assert.equals(res[0].diagnostics[0].args, "Invalid version string \"foo\". Should follow SemVer."); + }); } } diff --git a/tests/server/src/cases/display/issues/Issue9705.hx b/tests/server/src/cases/display/issues/Issue9705.hx index 9d8e986a267..c3db07c6e2b 100644 --- a/tests/server/src/cases/display/issues/Issue9705.hx +++ b/tests/server/src/cases/display/issues/Issue9705.hx @@ -6,11 +6,13 @@ class Issue9705 extends TestCase { function test(_) { vfs.putContent("Main.hx", getTemplate("issues/Issue9705/Main.hx")); var args = ["Main", "--interp"]; - runHaxe(args.concat(["--display", "Main.hx@0@diagnostics"])); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(1, res.length); + Assert.equals(1, res[0].diagnostics.length); + Assert.equals(DKUnresolvedIdentifier, res[0].diagnostics[0].kind); - var diag = parseDiagnostics(); - var range = diag[0].range; - Assert.equals(DKUnresolvedIdentifier, diag[0].kind); - Assert.equals("Arrey".length, range.end.character - range.start.character); + var range = res[0].diagnostics[0].range; + Assert.equals("Arrey".length, range.end.character - range.start.character); + }); } } diff --git a/tests/server/src/cases/issues/Issue10653.hx b/tests/server/src/cases/issues/Issue10653.hx index e855ac0e61e..2ebfa0b4fd1 100644 --- a/tests/server/src/cases/issues/Issue10653.hx +++ b/tests/server/src/cases/issues/Issue10653.hx @@ -8,9 +8,12 @@ class Issue10653 extends TestCase { runHaxe(args); vfs.putContent("Main.hx", getTemplate("issues/Issue10653/MainAfter.hx")); runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); - runHaxe(args.concat(["--display", "Main.hx@0@diagnostics"])); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(0, res.length); + }); runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); - runHaxe(args.concat(["--display", "Main.hx@0@diagnostics"])); - Assert.isTrue(lastResult.stderr.length == 2); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(0, res.length); + }); } } diff --git a/tests/server/src/cases/issues/Issue11177.hx b/tests/server/src/cases/issues/Issue11177.hx index 44caa3500df..38528afba39 100644 --- a/tests/server/src/cases/issues/Issue11177.hx +++ b/tests/server/src/cases/issues/Issue11177.hx @@ -6,12 +6,15 @@ class Issue11177 extends TestCase { vfs.putContent("Buttons.hx", getTemplate("issues/Issue11177/Buttons.hx")); vfs.putContent("KeyCode.hx", getTemplate("issues/Issue11177/KeyCode.hx")); var args = ["-main", "Main", "--interp"]; - runHaxe(args.concat(["--display", "Buttons.hx@0@diagnostics"])); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Buttons.hx")}, res -> { + Assert.equals(0, res.length); + }); vfs.putContent("Main.hx", getTemplate("issues/Issue11177/Main2.hx")); runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); runHaxe(args); - runHaxe(args.concat(["--display", "Buttons.hx@0@diagnostics"])); - Assert.isTrue(lastResult.stderr.length == 2); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Buttons.hx")}, res -> { + Assert.equals(0, res.length); + }); } function testWithoutCacheFromDisplay(_) { @@ -20,11 +23,14 @@ class Issue11177 extends TestCase { vfs.putContent("KeyCode.hx", getTemplate("issues/Issue11177/KeyCode.hx")); var args = ["-main", "Main", "--interp"]; runHaxeJson([], ServerMethods.Configure, {populateCacheFromDisplay: false}); - runHaxe(args.concat(["--display", "Buttons.hx@0@diagnostics"])); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Buttons.hx")}, res -> { + Assert.equals(0, res.length); + }); vfs.putContent("Main.hx", getTemplate("issues/Issue11177/Main2.hx")); runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); runHaxe(args); - runHaxe(args.concat(["--display", "Buttons.hx@0@diagnostics"])); - Assert.isTrue(lastResult.stderr.length == 2); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Buttons.hx")}, res -> { + Assert.equals(0, res.length); + }); } } diff --git a/tests/server/src/cases/issues/Issue11184.hx b/tests/server/src/cases/issues/Issue11184.hx index 1bfc1fa0621..254cbbf09ff 100644 --- a/tests/server/src/cases/issues/Issue11184.hx +++ b/tests/server/src/cases/issues/Issue11184.hx @@ -5,9 +5,11 @@ class Issue11184 extends TestCase { vfs.putContent("Main.hx", getTemplate("issues/Issue11184/Main.hx")); var args = ["-main", "Main", "-js", "bin/test.js"]; - runHaxe(args.concat(["--display", "Main.hx@0@diagnostics"])); - final diagnostics = haxe.Json.parse(lastResult.stderr)[0].diagnostics; - Assert.equals(diagnostics[0].args, "Cannot use Void as value"); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(1, res.length); + Assert.equals(1, res[0].diagnostics.length); + Assert.equals(res[0].diagnostics[0].args, "Cannot use Void as value"); + }); runHaxe(args); Assert.isTrue(hasErrorMessage("Cannot use Void as value")); @@ -19,7 +21,11 @@ class Issue11184 extends TestCase { vfs.putContent("Main.hx", getTemplate("issues/Issue11184/Main.hx")); var args = ["-main", "Main", "-js", "bin/test.js"]; runHaxeJson([], ServerMethods.Configure, {populateCacheFromDisplay: false}); - runHaxe(args.concat(["--display", "Main.hx@0@diagnostics"])); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(1, res.length); + Assert.equals(1, res[0].diagnostics.length); + Assert.equals(res[0].diagnostics[0].args, "Cannot use Void as value"); + }); runHaxe(args); Assert.isTrue(hasErrorMessage("Cannot use Void as value")); runHaxe(args); diff --git a/tests/server/src/cases/issues/Issue11203.hx b/tests/server/src/cases/issues/Issue11203.hx index f28726dcd13..f54818ee260 100644 --- a/tests/server/src/cases/issues/Issue11203.hx +++ b/tests/server/src/cases/issues/Issue11203.hx @@ -5,19 +5,17 @@ class Issue11203 extends TestCase { vfs.putContent("Main.hx", getTemplate("issues/Issue11203/MainClass.hx")); var args = ["Main", "--interp"]; runHaxe(args); - runHaxe(args.concat(["--display", "Main.hx@0@diagnostics"])); - - var diag = parseDiagnostics(); - Assert.isTrue(diag.length == 0); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(0, res.length); + }); } function testAbstract(_) { vfs.putContent("Main.hx", getTemplate("issues/Issue11203/MainAbstract.hx")); var args = ["Main", "--interp"]; runHaxe(args); - runHaxe(args.concat(["--display", "Main.hx@0@diagnostics"])); - - var diag = parseDiagnostics(); - Assert.isTrue(diag.length == 0); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals(0, res.length); + }); } } diff --git a/tests/server/test/templates/issues/Issue9134/Main.hx b/tests/server/test/templates/issues/Issue9134/Main.hx new file mode 100644 index 00000000000..7d765b265c8 --- /dev/null +++ b/tests/server/test/templates/issues/Issue9134/Main.hx @@ -0,0 +1,5 @@ +class Main { + static function main() { + var unused = null; + } +} diff --git a/tests/server/test/templates/issues/Issue9134/Main2.hx b/tests/server/test/templates/issues/Issue9134/Main2.hx new file mode 100644 index 00000000000..89552046053 --- /dev/null +++ b/tests/server/test/templates/issues/Issue9134/Main2.hx @@ -0,0 +1,6 @@ +class Main { + static function main() { + var unused = null; + if (unused != null) trace("wat"); + } +} diff --git a/tests/server/test/templates/issues/Issue9134/Other.hx b/tests/server/test/templates/issues/Issue9134/Other.hx new file mode 100644 index 00000000000..1b94418eb0a --- /dev/null +++ b/tests/server/test/templates/issues/Issue9134/Other.hx @@ -0,0 +1,2 @@ +class Other { +} diff --git a/tests/server/test/templates/issues/Issue9134/Other2.hx b/tests/server/test/templates/issues/Issue9134/Other2.hx new file mode 100644 index 00000000000..b74611cfa00 --- /dev/null +++ b/tests/server/test/templates/issues/Issue9134/Other2.hx @@ -0,0 +1,6 @@ +class Other { + static function foo() { + // var foo = trace("wat"); + var unused = null; + } +} From 32f04b9c4541be7ccea2906673f7e32e9ae07213 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Sun, 26 Nov 2023 17:04:39 +0100 Subject: [PATCH 005/184] [compiler] re-prioritze share over lib on unix systems Also remove extraLibs because I don't know what it is. Related issue is #1818, but after reading that I still don't know what it is. --- src/compiler/compiler.ml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index b38404939ab..ceb60f839a0 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -205,18 +205,14 @@ module Setup = struct let share_path = Filename.concat prefix_path "share" in [ ""; - Path.add_trailing_slash (Filename.concat lib_path "haxe/std"); - Path.add_trailing_slash (Filename.concat lib_path "haxe/extraLibs"); Path.add_trailing_slash (Filename.concat share_path "haxe/std"); - Path.add_trailing_slash (Filename.concat share_path "haxe/extraLibs"); + Path.add_trailing_slash (Filename.concat lib_path "haxe/std"); Path.add_trailing_slash (Filename.concat base_path "std"); - Path.add_trailing_slash (Filename.concat base_path "extraLibs") ] else [ ""; Path.add_trailing_slash (Filename.concat base_path "std"); - Path.add_trailing_slash (Filename.concat base_path "extraLibs") ] let setup_common_context ctx = From 7236c98e7d1d5c2eb68a56825722f21b0cad7e73 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Sun, 26 Nov 2023 17:06:32 +0100 Subject: [PATCH 006/184] Split up `check_overriding` (#11415) * parity * don't check overloads multiple times --- src/typing/typeloadCheck.ml | 170 +++++++++++++++++++++-------------- src/typing/typeloadFields.ml | 20 ++++- 2 files changed, 120 insertions(+), 70 deletions(-) diff --git a/src/typing/typeloadCheck.ml b/src/typing/typeloadCheck.ml index fc25dce2904..b9030afd9c5 100644 --- a/src/typing/typeloadCheck.ml +++ b/src/typing/typeloadCheck.ml @@ -165,71 +165,102 @@ let check_native_name_override ctx child base = error base.cf_name_pos child_pos with Not_found -> () +type redefinition_context = { + c_new : tclass; + cf_new : tclass_field; + c_old : tclass; + cf_old : tclass_field; + map : Type.t -> Type.t; + t_old : Type.t; +} + +let check_override_field ctx p rctx = + let i = rctx.cf_new.cf_name in + let f_has_override = has_class_field_flag rctx.cf_new CfOverride in + check_native_name_override ctx rctx.cf_new rctx.cf_old; + (* allow to define fields that are not defined for this platform version in superclass *) + (match rctx.cf_new.cf_kind with + | Var { v_read = AccRequire _ } -> raise Not_found; + | _ -> ()); + if has_class_field_flag rctx.cf_old CfAbstract then begin + if f_has_override then + display_error ctx.com ("Field " ^ i ^ " is declared 'override' but parent field " ^ i ^ " is 'abstract' and does not provide any implementation to override") p + else + add_class_field_flag rctx.cf_new CfOverride (* our spec requires users to not "override" abstract functions, but our implementation depends on implementations to be declared with "override" ¯\_(ツ)_/¯ *) + end; + if (has_class_field_flag rctx.cf_old CfOverload && not (has_class_field_flag rctx.cf_new CfOverload)) then + display_error ctx.com ("Field " ^ i ^ " should be declared with overload since it was already declared as overload in superclass") p + else if not f_has_override && not (has_class_field_flag rctx.cf_old CfAbstract) then begin + if has_class_flag rctx.c_new CExtern then add_class_field_flag rctx.cf_new CfOverride + else display_error ctx.com ("Field " ^ i ^ " should be declared with 'override' since it is inherited from superclass " ^ s_type_path rctx.c_old.cl_path) p + end else if not (has_class_field_flag rctx.cf_new CfPublic) && (has_class_field_flag rctx.cf_old CfPublic) then + display_error ctx.com ("Field " ^ i ^ " has less visibility (public/private) than superclass one") p + else (match rctx.cf_new.cf_kind, rctx.cf_old.cf_kind with + | _, Method MethInline -> + display_error ctx.com ("Field " ^ i ^ " is inlined and cannot be overridden") p + | a, b when a = b -> () + | Method MethInline, Method MethNormal -> + () (* allow to redefine a method as inlined *) + | _ -> + display_error ctx.com ("Field " ^ i ^ " has different property access than in superclass") p); + if (has_class_field_flag rctx.cf_old CfFinal) then display_error ctx.com ("Cannot override final method " ^ i) p; + try + valid_redefinition ctx rctx.map rctx.map rctx.cf_new rctx.cf_new.cf_type rctx.cf_old rctx.t_old; + with + Unify_error l -> + (* TODO construct error with sub *) + display_error ctx.com ("Field " ^ i ^ " overrides parent class with different or incomplete type") p; + display_error ~depth:1 ctx.com (compl_msg "Base field is defined here") rctx.cf_old.cf_name_pos; + display_error ~depth:1 ctx.com (compl_msg (error_msg (Unify l))) p + +let find_override_field ctx c_new cf_new c_old tl get_super_field is_overload p = + let i = cf_new.cf_name in + try + if is_overload && not (has_class_field_flag cf_new CfOverload) then + display_error ctx.com ("Missing overload declaration for field " ^ i) p; + let t, f2 = get_super_field c_old i in + let map = TClass.get_map_function c_old tl in + let rctx = { + c_new = c_new; + cf_new = cf_new; + c_old = c_old; + cf_old = f2; + map = map; + t_old = map t; + } in + Some rctx + with Not_found -> + if has_class_field_flag cf_new CfOverride then begin + let msg = if is_overload then + ("Field " ^ i ^ " is declared 'override' but no compatible overload was found") + else begin + let fields = TClass.get_all_super_fields c_new in + let fields = PMap.fold (fun (_,cf) acc -> match cf.cf_kind with + | Method MethNormal when not (has_class_field_flag cf CfFinal) -> cf.cf_name :: acc + | _ -> acc + ) fields [] in + StringError.string_error i fields ("Field " ^ i ^ " is declared 'override' but doesn't override any field") + end in + display_error ctx.com msg p; + end; + None + +type check_override_kind = + | NothingToDo + | NormalOverride of redefinition_context + | OverloadOverride of (unit -> unit) + let check_overriding ctx c f = match c.cl_super with | None -> - if has_class_field_flag f CfOverride then display_error ctx.com ("Field " ^ f.cf_name ^ " is declared 'override' but doesn't override any field") f.cf_pos - | _ when (has_class_flag c CExtern) && Meta.has Meta.CsNative c.cl_meta -> () (* -net-lib specific: do not check overrides on extern CsNative classes *) + if has_class_field_flag f CfOverride then + display_error ctx.com ("Field " ^ f.cf_name ^ " is declared 'override' but doesn't override any field") f.cf_pos; + NothingToDo + | _ when (has_class_flag c CExtern) && Meta.has Meta.CsNative c.cl_meta -> + NothingToDo (* -net-lib specific: do not check overrides on extern CsNative classes *) | Some (csup,params) -> let p = f.cf_name_pos in let i = f.cf_name in - let check_field f get_super_field is_overload = try - (if is_overload && not (has_class_field_flag f CfOverload) then - display_error ctx.com ("Missing overload declaration for field " ^ i) p); - let f_has_override = has_class_field_flag f CfOverride in - let t, f2 = get_super_field csup i in - check_native_name_override ctx f f2; - (* allow to define fields that are not defined for this platform version in superclass *) - (match f2.cf_kind with - | Var { v_read = AccRequire _ } -> raise Not_found; - | _ -> ()); - if has_class_field_flag f2 CfAbstract then begin - if f_has_override then - display_error ctx.com ("Field " ^ i ^ " is declared 'override' but parent field " ^ i ^ " is 'abstract' and does not provide any implementation to override") p - else - add_class_field_flag f CfOverride (* our spec requires users to not "override" abstract functions, but our implementation depends on implementations to be declared with "override" ¯\_(ツ)_/¯ *) - end; - if (has_class_field_flag f2 CfOverload && not (has_class_field_flag f CfOverload)) then - display_error ctx.com ("Field " ^ i ^ " should be declared with overload since it was already declared as overload in superclass") p - else if not f_has_override && not (has_class_field_flag f2 CfAbstract) then begin - if has_class_flag c CExtern then add_class_field_flag f CfOverride - else display_error ctx.com ("Field " ^ i ^ " should be declared with 'override' since it is inherited from superclass " ^ s_type_path csup.cl_path) p - end else if not (has_class_field_flag f CfPublic) && (has_class_field_flag f2 CfPublic) then - display_error ctx.com ("Field " ^ i ^ " has less visibility (public/private) than superclass one") p - else (match f.cf_kind, f2.cf_kind with - | _, Method MethInline -> - display_error ctx.com ("Field " ^ i ^ " is inlined and cannot be overridden") p - | a, b when a = b -> () - | Method MethInline, Method MethNormal -> - () (* allow to redefine a method as inlined *) - | _ -> - display_error ctx.com ("Field " ^ i ^ " has different property access than in superclass") p); - if (has_class_field_flag f2 CfFinal) then display_error ctx.com ("Cannot override final method " ^ i) p; - try - let t = apply_params csup.cl_params params t in - let map = TClass.get_map_function csup params in - valid_redefinition ctx map map f f.cf_type f2 t; - with - Unify_error l -> - (* TODO construct error with sub *) - display_error ctx.com ("Field " ^ i ^ " overrides parent class with different or incomplete type") p; - display_error ~depth:1 ctx.com (compl_msg "Base field is defined here") f2.cf_name_pos; - display_error ~depth:1 ctx.com (compl_msg (error_msg (Unify l))) p; - with - Not_found -> - if has_class_field_flag f CfOverride then - let msg = if is_overload then - ("Field " ^ i ^ " is declared 'override' but no compatible overload was found") - else begin - let fields = TClass.get_all_super_fields c in - let fields = PMap.fold (fun (_,cf) acc -> match cf.cf_kind with - | Method MethNormal when not (has_class_field_flag cf CfFinal) -> cf.cf_name :: acc - | _ -> acc - ) fields [] in - StringError.string_error i fields ("Field " ^ i ^ " is declared 'override' but doesn't override any field") - end in - display_error ctx.com msg p - in if has_class_field_flag f CfOverload then begin let overloads = Overloads.get_overloads ctx.com csup i in List.iter (fun (t,f2) -> @@ -237,20 +268,27 @@ let check_overriding ctx c f = match f2.cf_kind with | Var _ -> display_error ctx.com ("A variable named '" ^ f2.cf_name ^ "' was already declared in a superclass") f.cf_pos - | _ -> () + | _ -> + () ) overloads; - List.iter (fun f -> + OverloadOverride (fun () -> (* find the exact field being overridden *) - check_field f (fun csup i -> + Option.may (check_override_field ctx p) (find_override_field ctx c f csup params (fun csup i -> List.find (fun (t,f2) -> Overloads.same_overload_args f.cf_type (apply_params csup.cl_params params t) f f2 ) overloads - ) true - ) (f :: f.cf_overloads) + ) true p) + ) end else - check_field f (fun csup i -> + let rctx = find_override_field ctx c f csup params (fun csup i -> let _, t, f2 = raw_class_field (fun f -> f.cf_type) csup params i in - t, f2) false + t, f2 + ) false p in + match rctx with + | None -> + NothingToDo + | Some rctx -> + NormalOverride rctx let class_field_no_interf c i = try diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index 2dc2f433f86..f95f6fbe888 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -951,11 +951,23 @@ module TypeBinding = struct cf.cf_type <- t | _ -> if Meta.has Meta.DisplayOverride cf.cf_meta then DisplayEmitter.check_field_modifiers ctx c cf fctx.override fctx.display_modifier; + let f_check = match fctx.field_kind with + | FKNormal when not fctx.is_static -> + begin match TypeloadCheck.check_overriding ctx c cf with + | NothingToDo -> + (fun () -> ()) + | NormalOverride rctx -> + (fun () -> + TypeloadCheck.check_override_field ctx cf.cf_name_pos rctx + ) + | OverloadOverride f -> + f + end + | _ -> + (fun () -> ()) + in let e = TypeloadFunction.type_function ctx args ret fmode e fctx.is_display_field p in - begin match fctx.field_kind with - | FKNormal when not fctx.is_static -> TypeloadCheck.check_overriding ctx c cf - | _ -> () - end; + f_check(); (* Disabled for now, see https://github.com/HaxeFoundation/haxe/issues/3033 *) (* List.iter (fun (v,_) -> if v.v_name <> "_" && has_mono v.v_type then warning ctx WTemp "Uninferred function argument, please add a type-hint" v.v_pos; From ddef63886e69bb78e7623820a20b5b06fc49ba50 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Sat, 25 Nov 2023 22:30:22 +0100 Subject: [PATCH 007/184] [display] get rid of TypeloadParse.current_stdin --- src/compiler/displayProcessing.ml | 8 ++++---- src/compiler/server.ml | 2 +- src/context/common.ml | 4 +++- src/context/display/diagnosticsPrinter.ml | 3 +-- src/context/display/displayJson.ml | 16 ++++++++++------ src/typing/typeloadParse.ml | 18 +++--------------- 6 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/compiler/displayProcessing.ml b/src/compiler/displayProcessing.ml index 580a9d708a1..ee26859e4f5 100644 --- a/src/compiler/displayProcessing.ml +++ b/src/compiler/displayProcessing.ml @@ -143,11 +143,11 @@ let process_display_file com actx = | DFPOnly when (DisplayPosition.display_position#get).pfile = file_input_marker -> actx.classes <- []; com.main_class <- None; - begin match !TypeloadParse.current_stdin with - | Some input -> - TypeloadParse.current_stdin := None; + begin match com.file_contents with + | Some [_, Some input] -> + com.file_contents <- None; DPKInput input - | None -> + | _ -> DPKNone end | dfp -> diff --git a/src/compiler/server.ml b/src/compiler/server.ml index 07c4257787e..aeb9773c25d 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -47,7 +47,7 @@ let parse_file cs com file p = and fkey = com.file_keys#get file in let is_display_file = DisplayPosition.display_position#is_in_file (com.file_keys#get ffile) in match is_display_file, !current_stdin with - | true, Some stdin when Common.defined com Define.DisplayStdin -> + | true, Some stdin when (com.file_contents <> None || Common.defined com Define.DisplayStdin) -> TypeloadParse.parse_file_from_string com file p stdin | _ -> let ftime = file_time ffile in diff --git a/src/context/common.ml b/src/context/common.ml index 745b85cbbeb..b81905db889 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -290,7 +290,7 @@ let s_compiler_stage = function type report_mode = | RMNone | RMLegacyDiagnostics of (Path.UniqueKey.t list) - | RMDiagnostics of (Path.UniqueKey.t * string option (* file contents *)) list + | RMDiagnostics of (Path.UniqueKey.t list) | RMStatistics class virtual ['key,'value] lookup = object(self) @@ -401,6 +401,7 @@ type context = { display_information : display_information; file_lookup_cache : (string,string option) lookup; file_keys : file_keys; + mutable file_contents : (Path.UniqueKey.t * string option) list option; readdir_cache : (string * string,(string array) option) lookup; parser_cache : (string,(type_def * pos) list) lookup; module_to_file : (path,string) lookup; @@ -876,6 +877,7 @@ let create compilation_step cs version args = }; file_lookup_cache = new hashtbl_lookup; file_keys = new file_keys; + file_contents = None; readdir_cache = new hashtbl_lookup; module_to_file = new hashtbl_lookup; stored_typed_exprs = new hashtbl_lookup; diff --git a/src/context/display/diagnosticsPrinter.ml b/src/context/display/diagnosticsPrinter.ml index 482fe05f48d..dd485713de5 100644 --- a/src/context/display/diagnosticsPrinter.ml +++ b/src/context/display/diagnosticsPrinter.ml @@ -27,8 +27,7 @@ let make_diagnostic kd p sev code args = { let is_diagnostics_file com file_key = match com.report_mode with | RMLegacyDiagnostics [] | RMDiagnostics [] -> true - | RMLegacyDiagnostics file_keys -> List.exists (fun key' -> file_key = key') file_keys - | RMDiagnostics file_keys -> List.exists (fun (key',_) -> file_key = key') file_keys + | RMLegacyDiagnostics file_keys | RMDiagnostics file_keys -> List.mem file_key file_keys | _ -> false module UnresolvedIdentifierSuggestion = struct diff --git a/src/context/display/displayJson.ml b/src/context/display/displayJson.ml index 2ce233bb8a9..2b73cce890c 100644 --- a/src/context/display/displayJson.ml +++ b/src/context/display/displayJson.ml @@ -60,11 +60,12 @@ class display_handler (jsonrpc : jsonrpc_handler) com (cs : CompilationCache.t) Path.get_full_path file ) file_input_marker in let pos = if requires_offset then jsonrpc#get_int_param "offset" else (-1) in - TypeloadParse.current_stdin := jsonrpc#get_opt_param (fun () -> + ignore(jsonrpc#get_opt_param (fun () -> let s = jsonrpc#get_string_param "contents" in - Common.define com Define.DisplayStdin; (* TODO: awkward *) + let file_unique = com.file_keys#get file in + com.file_contents <- Some [file_unique, Some s]; Some s - ) None; + ) None); Parser.was_auto_triggered := was_auto_triggered; DisplayPosition.display_position#set { pfile = file; @@ -147,7 +148,8 @@ let handler = pmax = -1; }; - hctx.com.report_mode <- RMDiagnostics [file_unique, contents]; + hctx.com.file_contents <- Some [file_unique, contents]; + hctx.com.report_mode <- RMDiagnostics [file_unique]; hctx.com.display <- { hctx.com.display with dms_display_file_policy = DFPAlso; dms_per_file = true; dms_populate_cache = !ServerConfig.populate_cache_from_display}; end else begin let file_contents = hctx.jsonrpc#get_opt_param (fun () -> @@ -170,8 +172,10 @@ let handler = | _ -> invalid_arg "fileContents" ) file_contents in - DisplayPosition.display_position#set_files (List.map (fun (k, _) -> k) file_contents); - hctx.com.report_mode <- RMDiagnostics file_contents + let files = (List.map (fun (k, _) -> k) file_contents) in + DisplayPosition.display_position#set_files files; + hctx.com.file_contents <- Some file_contents; + hctx.com.report_mode <- RMDiagnostics files end ); "display/implementation", (fun hctx -> diff --git a/src/typing/typeloadParse.ml b/src/typing/typeloadParse.ml index 208b3714fdd..9b23d97c664 100644 --- a/src/typing/typeloadParse.ml +++ b/src/typing/typeloadParse.ml @@ -58,23 +58,11 @@ let parse_file_from_lexbuf com file p lexbuf = let parse_file_from_string com file p string = parse_file_from_lexbuf com file p (Sedlexing.Utf8.from_string string) -let current_stdin = ref None (* TODO: we're supposed to clear this at some point *) - let parse_file com file p = - let contents = match com.report_mode with - | RMDiagnostics files -> + let contents = match com.file_contents with + | Some files -> (try List.assoc (com.file_keys#get file) files with Not_found -> None) - | _ when (Common.defined com Define.DisplayStdin) && DisplayPosition.display_position#is_in_file (com.file_keys#get file) -> - Some (match !current_stdin with - | Some s -> - s - | None -> - let s = Std.input_all stdin in - close_in stdin; - current_stdin := Some s; - s - ) - | _ -> None + | None -> None in match contents with From e4ca1c81f00082a22caa3fcde4663bd822caf2fb Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Sun, 26 Nov 2023 09:25:53 +0100 Subject: [PATCH 008/184] [display] fix -D display-stdin handling --- src/context/display/displayJson.ml | 7 +++---- src/typing/typeloadParse.ml | 8 +++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/context/display/displayJson.ml b/src/context/display/displayJson.ml index 2b73cce890c..096821af655 100644 --- a/src/context/display/displayJson.ml +++ b/src/context/display/displayJson.ml @@ -60,12 +60,11 @@ class display_handler (jsonrpc : jsonrpc_handler) com (cs : CompilationCache.t) Path.get_full_path file ) file_input_marker in let pos = if requires_offset then jsonrpc#get_int_param "offset" else (-1) in - ignore(jsonrpc#get_opt_param (fun () -> + com.file_contents <- jsonrpc#get_opt_param (fun () -> let s = jsonrpc#get_string_param "contents" in let file_unique = com.file_keys#get file in - com.file_contents <- Some [file_unique, Some s]; - Some s - ) None); + Some [file_unique, Some s] + ) None; Parser.was_auto_triggered := was_auto_triggered; DisplayPosition.display_position#set { pfile = file; diff --git a/src/typing/typeloadParse.ml b/src/typing/typeloadParse.ml index 9b23d97c664..886aada906b 100644 --- a/src/typing/typeloadParse.ml +++ b/src/typing/typeloadParse.ml @@ -59,9 +59,15 @@ let parse_file_from_string com file p string = parse_file_from_lexbuf com file p (Sedlexing.Utf8.from_string string) let parse_file com file p = + let file_key = com.file_keys#get file in let contents = match com.file_contents with | Some files -> - (try List.assoc (com.file_keys#get file) files with Not_found -> None) + (try List.assoc file_key files with Not_found -> None) + | None when (Common.defined com Define.DisplayStdin) && DisplayPosition.display_position#is_in_file file_key -> + let s = Std.input_all stdin in + close_in stdin; + com.file_contents <- Some [file_key, Some s]; + Some s | None -> None in From 19cc8a50d3f90d1afa0452e7cf5ae0867106fc37 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Sun, 26 Nov 2023 14:26:07 +0100 Subject: [PATCH 009/184] [display] generalize fileContents behavior to other json rpc display calls --- src/compiler/displayProcessing.ml | 4 +- src/compiler/server.ml | 2 +- src/context/common.ml | 4 +- src/context/display/displayJson.ml | 103 ++++++++++++-------------- src/typing/typeloadParse.ml | 10 +-- tests/server/src/cases/ServerTests.hx | 27 +++++++ 6 files changed, 83 insertions(+), 67 deletions(-) diff --git a/src/compiler/displayProcessing.ml b/src/compiler/displayProcessing.ml index ee26859e4f5..70c217d91fe 100644 --- a/src/compiler/displayProcessing.ml +++ b/src/compiler/displayProcessing.ml @@ -144,8 +144,8 @@ let process_display_file com actx = actx.classes <- []; com.main_class <- None; begin match com.file_contents with - | Some [_, Some input] -> - com.file_contents <- None; + | [_, Some input] -> + com.file_contents <- []; DPKInput input | _ -> DPKNone diff --git a/src/compiler/server.ml b/src/compiler/server.ml index aeb9773c25d..de6edffc75c 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -47,7 +47,7 @@ let parse_file cs com file p = and fkey = com.file_keys#get file in let is_display_file = DisplayPosition.display_position#is_in_file (com.file_keys#get ffile) in match is_display_file, !current_stdin with - | true, Some stdin when (com.file_contents <> None || Common.defined com Define.DisplayStdin) -> + | true, Some stdin when (com.file_contents <> [] || Common.defined com Define.DisplayStdin) -> TypeloadParse.parse_file_from_string com file p stdin | _ -> let ftime = file_time ffile in diff --git a/src/context/common.ml b/src/context/common.ml index b81905db889..10c6e484f40 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -401,7 +401,7 @@ type context = { display_information : display_information; file_lookup_cache : (string,string option) lookup; file_keys : file_keys; - mutable file_contents : (Path.UniqueKey.t * string option) list option; + mutable file_contents : (Path.UniqueKey.t * string option) list; readdir_cache : (string * string,(string array) option) lookup; parser_cache : (string,(type_def * pos) list) lookup; module_to_file : (path,string) lookup; @@ -877,7 +877,7 @@ let create compilation_step cs version args = }; file_lookup_cache = new hashtbl_lookup; file_keys = new file_keys; - file_contents = None; + file_contents = []; readdir_cache = new hashtbl_lookup; module_to_file = new hashtbl_lookup; stored_typed_exprs = new hashtbl_lookup; diff --git a/src/context/display/displayJson.ml b/src/context/display/displayJson.ml index 096821af655..986a86ee285 100644 --- a/src/context/display/displayJson.ml +++ b/src/context/display/displayJson.ml @@ -59,18 +59,49 @@ class display_handler (jsonrpc : jsonrpc_handler) com (cs : CompilationCache.t) let file = jsonrpc#get_string_param "file" in Path.get_full_path file ) file_input_marker in - let pos = if requires_offset then jsonrpc#get_int_param "offset" else (-1) in - com.file_contents <- jsonrpc#get_opt_param (fun () -> + let contents = jsonrpc#get_opt_param (fun () -> let s = jsonrpc#get_string_param "contents" in - let file_unique = com.file_keys#get file in - Some [file_unique, Some s] - ) None; + Some s + ) None in + + let pos = if requires_offset then jsonrpc#get_int_param "offset" else (-1) in Parser.was_auto_triggered := was_auto_triggered; - DisplayPosition.display_position#set { - pfile = file; - pmin = pos; - pmax = pos; - } + + if file <> file_input_marker then begin + let file_unique = com.file_keys#get file in + + DisplayPosition.display_position#set { + pfile = file; + pmin = pos; + pmax = pos; + }; + + com.file_contents <- [file_unique, contents]; + end else begin + let file_contents = jsonrpc#get_opt_param (fun () -> + jsonrpc#get_opt_param (fun () -> jsonrpc#get_array_param "fileContents") [] + ) [] in + + let file_contents = List.map (fun fc -> match fc with + | JObject fl -> + let file = jsonrpc#get_string_field "fileContents" "file" fl in + let file = Path.get_full_path file in + let file_unique = com.file_keys#get file in + let contents = jsonrpc#get_opt_param (fun () -> + let s = jsonrpc#get_string_field "fileContents" "contents" fl in + Some s + ) None in + (file_unique, contents) + | _ -> invalid_arg "fileContents" + ) file_contents in + + let files = (List.map (fun (k, _) -> k) file_contents) in + com.file_contents <- file_contents; + + match files with + | [] | [_] -> DisplayPosition.display_position#set { pfile = file; pmin = pos; pmax = pos; }; + | _ -> DisplayPosition.display_position#set_files files; + end end type handler_context = { @@ -126,56 +157,14 @@ let handler = hctx.display#enable_display DMDefinition; ); "display/diagnostics", (fun hctx -> + hctx.display#set_display_file false false; hctx.display#enable_display DMNone; + hctx.com.report_mode <- RMDiagnostics (List.map (fun (f,_) -> f) hctx.com.file_contents); - let file = hctx.jsonrpc#get_opt_param (fun () -> - let file = hctx.jsonrpc#get_string_param "file" in - Path.get_full_path file - ) file_input_marker in - - if file <> file_input_marker then begin - let file_unique = hctx.com.file_keys#get file in - - let contents = hctx.jsonrpc#get_opt_param (fun () -> - let s = hctx.jsonrpc#get_string_param "contents" in - Some s - ) None in - - DisplayPosition.display_position#set { - pfile = file; - pmin = -1; - pmax = -1; - }; - - hctx.com.file_contents <- Some [file_unique, contents]; - hctx.com.report_mode <- RMDiagnostics [file_unique]; + (match hctx.com.file_contents with + | [file, None] -> hctx.com.display <- { hctx.com.display with dms_display_file_policy = DFPAlso; dms_per_file = true; dms_populate_cache = !ServerConfig.populate_cache_from_display}; - end else begin - let file_contents = hctx.jsonrpc#get_opt_param (fun () -> - hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_array_param "fileContents") [] - ) [] in - - if (List.length file_contents) = 0 then begin - hctx.com.report_mode <- RMDiagnostics [] - end else - let file_contents = List.map (fun fc -> match fc with - | JObject fl -> - let file = hctx.jsonrpc#get_string_field "fileContents" "file" fl in - let file = Path.get_full_path file in - let file_unique = hctx.com.file_keys#get file in - let contents = hctx.jsonrpc#get_opt_param (fun () -> - let s = hctx.jsonrpc#get_string_field "fileContents" "contents" fl in - Some s - ) None in - (file_unique, contents) - | _ -> invalid_arg "fileContents" - ) file_contents in - - let files = (List.map (fun (k, _) -> k) file_contents) in - DisplayPosition.display_position#set_files files; - hctx.com.file_contents <- Some file_contents; - hctx.com.report_mode <- RMDiagnostics files - end + | _ -> ()); ); "display/implementation", (fun hctx -> hctx.display#set_display_file false true; diff --git a/src/typing/typeloadParse.ml b/src/typing/typeloadParse.ml index 886aada906b..481c451236d 100644 --- a/src/typing/typeloadParse.ml +++ b/src/typing/typeloadParse.ml @@ -61,14 +61,14 @@ let parse_file_from_string com file p string = let parse_file com file p = let file_key = com.file_keys#get file in let contents = match com.file_contents with - | Some files -> - (try List.assoc file_key files with Not_found -> None) - | None when (Common.defined com Define.DisplayStdin) && DisplayPosition.display_position#is_in_file file_key -> + | [] when (Common.defined com Define.DisplayStdin) && DisplayPosition.display_position#is_in_file file_key -> let s = Std.input_all stdin in close_in stdin; - com.file_contents <- Some [file_key, Some s]; + com.file_contents <- [file_key, Some s]; Some s - | None -> None + | [] -> None + | files -> + (try List.assoc file_key files with Not_found -> None) in match contents with diff --git a/tests/server/src/cases/ServerTests.hx b/tests/server/src/cases/ServerTests.hx index 3dbe47d7f7e..80f00ee03b4 100644 --- a/tests/server/src/cases/ServerTests.hx +++ b/tests/server/src/cases/ServerTests.hx @@ -190,6 +190,33 @@ class ServerTests extends TestCase { Assert.equals("Unused variable", (cast arg).description); } }); + + // Currently, haxe compilation server will have this content anyway + // because of diagnostics with file contents, but that behavior may not + // be obvious in tests + vfs.putContent("Other.hx", getTemplate("issues/Issue9134/Other2.hx")); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Other.hx")}); + + // Running project wide diagnostics; checks here aren't great since + // results will depend on haxe std which may change without updating + // this test everytime.. + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {}, res -> { + var hasMain = false; + var hasOther = false; + + for (result in res) { + var file = result.file.toString(); + if (StringTools.endsWith(file, "Main.hx")) hasMain = true; + else if (StringTools.endsWith(file, "Other.hx")) hasOther = true; + else continue; + + var arg = result.diagnostics[0].args; + Assert.equals("Unused variable", (cast arg).description); + } + + Assert.isTrue(hasMain); + Assert.isTrue(hasOther); + }); } function testDiagnosticsRecache() { From bf7a769963bc9d7dfca6be84616f9d0e0076aba0 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 29 Nov 2023 15:03:09 +0100 Subject: [PATCH 010/184] [tests] improve json rpc handling --- tests/misc/src/Main.hx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/misc/src/Main.hx b/tests/misc/src/Main.hx index 7c8dc2c05cd..4f387cc95d1 100644 --- a/tests/misc/src/Main.hx +++ b/tests/misc/src/Main.hx @@ -151,6 +151,14 @@ class Main { .filter(s -> 0 != s.indexOf('Picked up JAVA_TOOL_OPTIONS:')) .join('\n'); + if (StringTools.startsWith(content, '{"jsonrpc":')) { + try { + content = haxe.Json.stringify(haxe.Json.parse(content).result.result); + // Reorder fields from expected too + expected = haxe.Json.stringify(haxe.Json.parse(expected)); + } catch (_) {} + } + if (content != expected) { final a = new diff.FileData(Bytes.ofString(expected), "expected", Date.now()); final b = new diff.FileData(Bytes.ofString(content), "actual", Date.now()); From 0809c0ddf5a1c734eadbb65b42e284ef5e83fb91 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Sat, 25 Nov 2023 23:02:18 +0100 Subject: [PATCH 011/184] [tests] migrate last legacy diagnostics in server tests --- tests/server/src/cases/ServerTests.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/server/src/cases/ServerTests.hx b/tests/server/src/cases/ServerTests.hx index 80f00ee03b4..8605bc44ff1 100644 --- a/tests/server/src/cases/ServerTests.hx +++ b/tests/server/src/cases/ServerTests.hx @@ -486,7 +486,7 @@ class ServerTests extends TestCase { var runs = 0; function runLoop() { - runHaxe(args.concat(["--display", "Empty.hx@0@diagnostics"]), () -> { + runHaxeJson(args, DisplayMethods.Diagnostics, {file: new FsPath("Empty.hx")}, () -> { runHaxe(args.concat(["-D", "compile-only-define"]), () -> { if (assertSuccess() && ++runs < 20) runLoop(); else async.done(); From 7bcbb2510574729e2bc9f20660436015d2be49c9 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 29 Nov 2023 18:37:25 +0100 Subject: [PATCH 012/184] [tests] add test for #7282 --- tests/server/src/cases/issues/Issue7282.hx | 13 +++++++++++++ .../server/test/templates/issues/Issue7282/Main.hx | 10 ++++++++++ 2 files changed, 23 insertions(+) create mode 100644 tests/server/src/cases/issues/Issue7282.hx create mode 100644 tests/server/test/templates/issues/Issue7282/Main.hx diff --git a/tests/server/src/cases/issues/Issue7282.hx b/tests/server/src/cases/issues/Issue7282.hx new file mode 100644 index 00000000000..52c5e45eaea --- /dev/null +++ b/tests/server/src/cases/issues/Issue7282.hx @@ -0,0 +1,13 @@ +package cases.issues; + +class Issue7282 extends TestCase { + function test(_) { + vfs.putContent("Main.hx", getTemplate("issues/Issue7282/Main.hx")); + var args = ["-main", "Main"]; + runHaxe(args); + assertSuccess(); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals("Unused variable", (cast res[0].diagnostics[0].args).description); + }); + } +} diff --git a/tests/server/test/templates/issues/Issue7282/Main.hx b/tests/server/test/templates/issues/Issue7282/Main.hx new file mode 100644 index 00000000000..c0e2ff75328 --- /dev/null +++ b/tests/server/test/templates/issues/Issue7282/Main.hx @@ -0,0 +1,10 @@ +import haxe.ds.Option; + +class Main { + public static function main() { + switch ((null:Option)) { + case Some(value): + case None: + } + } +} From d62489bc51d62667484200cf2ad0f04c06a7c3ef Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 29 Nov 2023 18:37:37 +0100 Subject: [PATCH 013/184] [tests] add test for #7931 --- tests/server/src/cases/issues/Issue7931.hx | 13 +++++++++++++ .../server/test/templates/issues/Issue7931/Main.hx | 6 ++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/server/src/cases/issues/Issue7931.hx create mode 100644 tests/server/test/templates/issues/Issue7931/Main.hx diff --git a/tests/server/src/cases/issues/Issue7931.hx b/tests/server/src/cases/issues/Issue7931.hx new file mode 100644 index 00000000000..2a640eedabb --- /dev/null +++ b/tests/server/src/cases/issues/Issue7931.hx @@ -0,0 +1,13 @@ +package cases.issues; + +class Issue7931 extends TestCase { + function test(_) { + vfs.putContent("Main.hx", getTemplate("issues/Issue7931/Main.hx")); + var args = ["-main", "Main"]; + runHaxe(args); + assertErrorMessage("Local variable s used without being initialized"); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { + Assert.equals("Local variable s used without being initialized", res[0].diagnostics[0].args); + }); + } +} diff --git a/tests/server/test/templates/issues/Issue7931/Main.hx b/tests/server/test/templates/issues/Issue7931/Main.hx new file mode 100644 index 00000000000..057ed3a1226 --- /dev/null +++ b/tests/server/test/templates/issues/Issue7931/Main.hx @@ -0,0 +1,6 @@ +class Main { + static function main() { + var s:String; + s += "test"; + } +} From b8b2dfccbfbac1005806accf8135c67b88bf4b52 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 30 Nov 2023 08:24:34 +0100 Subject: [PATCH 014/184] [tests] check for range too for #7282 --- tests/server/src/cases/issues/Issue7282.hx | 12 ++++++++++-- tests/server/test/templates/issues/Issue7282/Main.hx | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/server/src/cases/issues/Issue7282.hx b/tests/server/src/cases/issues/Issue7282.hx index 52c5e45eaea..9d24ab2af84 100644 --- a/tests/server/src/cases/issues/Issue7282.hx +++ b/tests/server/src/cases/issues/Issue7282.hx @@ -1,13 +1,21 @@ package cases.issues; +import haxe.display.Diagnostic; + class Issue7282 extends TestCase { function test(_) { - vfs.putContent("Main.hx", getTemplate("issues/Issue7282/Main.hx")); + var content = getTemplate("issues/Issue7282/Main.hx"); + var transform = Markers.parse(content); + + vfs.putContent("Main.hx", transform.source); var args = ["-main", "Main"]; runHaxe(args); assertSuccess(); runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { - Assert.equals("Unused variable", (cast res[0].diagnostics[0].args).description); + var arg:ReplacableCode = res[0].diagnostics[0].args; + Assert.equals("Unused variable", arg.description); + Assert.same(transform.range(1,2), res[0].diagnostics[0].range); + Assert.same(transform.range(1,2), arg.range); }); } } diff --git a/tests/server/test/templates/issues/Issue7282/Main.hx b/tests/server/test/templates/issues/Issue7282/Main.hx index c0e2ff75328..a36d330addf 100644 --- a/tests/server/test/templates/issues/Issue7282/Main.hx +++ b/tests/server/test/templates/issues/Issue7282/Main.hx @@ -3,7 +3,7 @@ import haxe.ds.Option; class Main { public static function main() { switch ((null:Option)) { - case Some(value): + case Some({-1-}value{-2-}): case None: } } From 3fc4bda3753f35ad650d1ff6ffe3dff18d1324d9 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 30 Nov 2023 08:28:00 +0100 Subject: [PATCH 015/184] [tests] be more specific for 7931 test --- tests/server/src/cases/issues/Issue7931.hx | 6 +++++- tests/server/test/templates/issues/Issue7931/Main.hx | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/server/src/cases/issues/Issue7931.hx b/tests/server/src/cases/issues/Issue7931.hx index 2a640eedabb..75c8334ca78 100644 --- a/tests/server/src/cases/issues/Issue7931.hx +++ b/tests/server/src/cases/issues/Issue7931.hx @@ -2,12 +2,16 @@ package cases.issues; class Issue7931 extends TestCase { function test(_) { - vfs.putContent("Main.hx", getTemplate("issues/Issue7931/Main.hx")); + var content = getTemplate("issues/Issue7931/Main.hx"); + var transform = Markers.parse(content); + + vfs.putContent("Main.hx", transform.source); var args = ["-main", "Main"]; runHaxe(args); assertErrorMessage("Local variable s used without being initialized"); runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { Assert.equals("Local variable s used without being initialized", res[0].diagnostics[0].args); + Assert.same(transform.range(1,2), res[0].diagnostics[0].range); }); } } diff --git a/tests/server/test/templates/issues/Issue7931/Main.hx b/tests/server/test/templates/issues/Issue7931/Main.hx index 057ed3a1226..fec091fa81a 100644 --- a/tests/server/test/templates/issues/Issue7931/Main.hx +++ b/tests/server/test/templates/issues/Issue7931/Main.hx @@ -1,6 +1,6 @@ class Main { static function main() { var s:String; - s += "test"; + {-1-}s{-2-} += "test"; } } From b24f35d456bd9582ce6be2ef7cacd41b01cfc3e9 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 30 Nov 2023 12:03:11 +0100 Subject: [PATCH 016/184] Remove hx4compat stuff (part 1) (#11386) * destroy * update haxelib submodule * submodule * submodule ffs * cppia * remove echoServer * remove more things * more * use patched utest for now * remove one more * try utest2 * fix test * explicitly pass `null` to the `type` argument of `utest.Assert.raises()` * [php] update test #9924 for compatibility with the latest utest * [tests] type-hint Vfs.getContent * fix Vfs.getContent one more time * fix display tests * switch to utest master --------- Co-authored-by: Aleksandr Kuzmenko --- std/cpp/_std/sys/db/Mysql.hx | 228 --------- std/cpp/_std/sys/db/Sqlite.hx | 203 -------- std/cpp/cppia/HostClasses.hx | 6 - std/cs/_std/sys/db/Sqlite.hx | 59 --- std/cs/db/AdoNet.hx | 354 ------------- std/hl/_std/sys/db/Connection.hx | 36 -- std/hl/_std/sys/db/Mysql.hx | 250 --------- std/hl/_std/sys/db/ResultSet.hx | 36 -- std/hl/_std/sys/db/Sqlite.hx | 283 ---------- std/java/_std/sys/db/Mysql.hx | 56 -- std/java/_std/sys/db/Sqlite.hx | 42 -- std/java/db/Jdbc.hx | 318 ------------ std/neko/Web.hx | 409 --------------- std/neko/_std/sys/db/Mysql.hx | 213 -------- std/neko/_std/sys/db/Sqlite.hx | 199 -------- std/php/Web.hx | 482 ------------------ std/php/_std/sys/db/Mysql.hx | 268 ---------- std/php/_std/sys/db/Sqlite.hx | 218 -------- std/php/db/Mysqli.hx | 100 ---- std/php/db/Mysqli_driver.hx | 38 -- std/php/db/Mysqli_result.hx | 62 --- std/php/db/Mysqli_stmt.hx | 57 --- std/php/db/Mysqli_warning.hx | 32 -- std/php/db/PDO.hx | 109 ---- std/php/db/PDOException.hx | 30 -- std/php/db/PDOStatement.hx | 48 -- std/php/db/SQLite3.hx | 50 -- std/php/db/SQLite3Result.hx | 36 -- std/php/db/SQLite3Stmt.hx | 38 -- std/sys/db/Connection.hx | 36 -- std/sys/db/Mysql.hx | 37 -- std/sys/db/ResultSet.hx | 70 --- std/sys/db/Sqlite.hx | 41 -- tests/RunCi.hx | 14 +- tests/echoServer/.gitignore | 1 - tests/echoServer/EchoServer.hx | 6 - tests/echoServer/build.hxml | 2 - tests/echoServer/www/crossdomain.xml | 7 - .../src/cases/display/issues/Issue8381.hx | 4 +- .../src/cases/display/issues/Issue8602.hx | 4 +- .../src/cases/display/issues/Issue8991.hx | 4 +- .../src/cases/display/issues/Issue9012.hx | 4 +- .../src/cases/display/issues/Issue9705.hx | 2 +- tests/server/src/utils/Vfs.hx | 4 +- tests/sys/src/Main.hx | 4 - tests/sys/src/db/SqliteSetup.hx | 27 - tests/sys/src/db/TestSqliteConnection.hx | 60 --- tests/sys/src/db/TestSqliteResultSet.hx | 62 --- tests/unit/src/RunExe.hx | 39 -- tests/unit/src/RunJava.hx | 17 - tests/unit/src/unit/Test.hx | 2 +- tests/unit/src/unit/TestHttp.hx | 81 --- tests/unit/src/unit/TestMain.hx | 8 - tests/unit/src/unit/TestPhp.hx | 132 ++--- tests/unit/src/unit/issues/Issue10876.hx | 16 +- tests/unit/src/unit/issues/Issue5270.hx | 17 - 56 files changed, 93 insertions(+), 4868 deletions(-) delete mode 100644 std/cpp/_std/sys/db/Mysql.hx delete mode 100644 std/cpp/_std/sys/db/Sqlite.hx delete mode 100644 std/cs/_std/sys/db/Sqlite.hx delete mode 100644 std/cs/db/AdoNet.hx delete mode 100644 std/hl/_std/sys/db/Connection.hx delete mode 100644 std/hl/_std/sys/db/Mysql.hx delete mode 100644 std/hl/_std/sys/db/ResultSet.hx delete mode 100644 std/hl/_std/sys/db/Sqlite.hx delete mode 100644 std/java/_std/sys/db/Mysql.hx delete mode 100644 std/java/_std/sys/db/Sqlite.hx delete mode 100644 std/java/db/Jdbc.hx delete mode 100644 std/neko/Web.hx delete mode 100644 std/neko/_std/sys/db/Mysql.hx delete mode 100644 std/neko/_std/sys/db/Sqlite.hx delete mode 100644 std/php/Web.hx delete mode 100644 std/php/_std/sys/db/Mysql.hx delete mode 100644 std/php/_std/sys/db/Sqlite.hx delete mode 100644 std/php/db/Mysqli.hx delete mode 100644 std/php/db/Mysqli_driver.hx delete mode 100644 std/php/db/Mysqli_result.hx delete mode 100644 std/php/db/Mysqli_stmt.hx delete mode 100644 std/php/db/Mysqli_warning.hx delete mode 100644 std/php/db/PDO.hx delete mode 100644 std/php/db/PDOException.hx delete mode 100644 std/php/db/PDOStatement.hx delete mode 100644 std/php/db/SQLite3.hx delete mode 100644 std/php/db/SQLite3Result.hx delete mode 100644 std/php/db/SQLite3Stmt.hx delete mode 100644 std/sys/db/Connection.hx delete mode 100644 std/sys/db/Mysql.hx delete mode 100644 std/sys/db/ResultSet.hx delete mode 100644 std/sys/db/Sqlite.hx delete mode 100644 tests/echoServer/.gitignore delete mode 100644 tests/echoServer/EchoServer.hx delete mode 100644 tests/echoServer/build.hxml delete mode 100644 tests/echoServer/www/crossdomain.xml delete mode 100644 tests/sys/src/db/SqliteSetup.hx delete mode 100644 tests/sys/src/db/TestSqliteConnection.hx delete mode 100644 tests/sys/src/db/TestSqliteResultSet.hx delete mode 100644 tests/unit/src/RunExe.hx delete mode 100644 tests/unit/src/RunJava.hx delete mode 100644 tests/unit/src/unit/TestHttp.hx delete mode 100644 tests/unit/src/unit/issues/Issue5270.hx diff --git a/std/cpp/_std/sys/db/Mysql.hx b/std/cpp/_std/sys/db/Mysql.hx deleted file mode 100644 index 86fb0febeb2..00000000000 --- a/std/cpp/_std/sys/db/Mysql.hx +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -@:keep -private class D { - @:native("_hx_mysql_connect") - extern public static function connect(params:Dynamic):Dynamic; - - @:native("_hx_mysql_select_db") - extern public static function select_db(handle:Dynamic, db:String):Void; - - @:native("_hx_mysql_request") - extern public static function request(handle:Dynamic, req:String):Dynamic; - - @:native("_hx_mysql_close") - extern public static function close(handle:Dynamic):Dynamic; - - @:native("_hx_mysql_escape") - extern public static function escape(handle:Dynamic, str:String):String; - - @:native("_hx_mysql_result_get_length") - extern public static function result_get_length(handle:Dynamic):Int; - - @:native("_hx_mysql_result_get_nfields") - extern public static function result_get_nfields(handle:Dynamic):Int; - - @:native("_hx_mysql_result_next") - extern public static function result_next(handle:Dynamic):Dynamic; - - @:native("_hx_mysql_result_get") - extern public static function result_get(handle:Dynamic, i:Int):String; - - @:native("_hx_mysql_result_get_int") - extern public static function result_get_int(handle:Dynamic, i:Int):Int; - - @:native("_hx_mysql_result_get_float") - extern public static function result_get_float(handle:Dynamic, i:Int):Float; - - @:native("_hx_mysql_result_get_fields_names") - extern public static function result_fields_names(handle:Dynamic):Array; - - @:native("_hx_mysql_set_conversion") - extern public static function set_conv_funs(charsToBytes:cpp.CallableDynamic>, intToDate:cpp.CallableDynamic>):Void; - - public static function charsToBytes(data:Dynamic):Dynamic - return haxe.io.Bytes.ofData(data); - - public static function secondsToDate(seconds:Float):Dynamic - return Date.fromTime(seconds * 1000); -} - -private class MysqlResultSet implements sys.db.ResultSet { - public var length(get, null):Int; - public var nfields(get, null):Int; - - private var __r:Dynamic; - private var cache:Dynamic; - - public function new(r:Dynamic) { - __r = r; - } - - private function get_length() { - return D.result_get_length(__r); - } - - private function get_nfields() { - return D.result_get_nfields(__r); - } - - public function hasNext() { - if (cache == null) - cache = next(); - return (cache != null); - } - - public function next():Dynamic { - var c = cache; - if (c != null) { - cache = null; - return c; - } - c = D.result_next(__r); - return c; - } - - public function results():List { - var l = new List(); - while (hasNext()) - l.add(next()); - return l; - } - - public function getResult(n:Int) { - return D.result_get(__r, n); - } - - public function getIntResult(n:Int):Int { - return D.result_get_int(__r, n); - } - - public function getFloatResult(n:Int):Float { - return D.result_get_float(__r, n); - } - - public function getFieldsNames():Array { - var a = D.result_fields_names(__r); - return a; - } -} - -private class MysqlConnection implements sys.db.Connection { - private var __c:Dynamic; - - public function new(c:Dynamic) { - __c = c; - D.set_conv_funs(cpp.Function.fromStaticFunction(D.charsToBytes), cpp.Function.fromStaticFunction(D.secondsToDate)); - } - - public function request(s:String):sys.db.ResultSet { - var r = D.request(this.__c, s); - return new MysqlResultSet(r); - } - - public function close() { - D.close(__c); - } - - public function escape(s:String) { - return D.escape(__c, s); - } - - public function quote(s:String) { - return "'" + escape(s) + "'"; - } - - public function addValue(s:StringBuf, v:Dynamic) { - if (v == null) { - s.add(v); - } else if (Std.isOfType(v, Bool)) { - s.add(v ? 1 : 0); - } else { - var t:Int = untyped v.__GetType(); - if (t == 0xff) - s.add(v); - else if (t == 2) - s.add(untyped v.__GetInt() ? "1".code : "0".code); - else { - s.addChar("'".code); - s.add(escape(Std.string(v))); - s.addChar("'".code); - } - } - } - - public function lastInsertId() { - return request("SELECT LAST_INSERT_ID()").getIntResult(0); - } - - public function dbName() { - return "MySQL"; - } - - public function startTransaction() { - request("START TRANSACTION"); - } - - public function commit() { - request("COMMIT"); - } - - public function rollback() { - request("ROLLBACK"); - } - - private static var __use_date = Date; -} - -@:buildXml('') -@:coreApi class Mysql { - public static function connect(params:{ - host:String, - ?port:Int, - user:String, - pass:String, - ?socket:String, - ?database:String - }):sys.db.Connection { - var o = { - host: params.host, - port: if (params.port == null) 3306 else params.port, - user: params.user, - pass: params.pass, - socket: if (params.socket == null) null else params.socket - }; - var c = D.connect(o); - if (params.database != null) { - try { - D.select_db(c, params.database); - } catch (e:Dynamic) { - D.close(c); - cpp.Lib.rethrow(e); - } - } - return new MysqlConnection(c); - } -} diff --git a/std/cpp/_std/sys/db/Sqlite.hx b/std/cpp/_std/sys/db/Sqlite.hx deleted file mode 100644 index 7ab123443c5..00000000000 --- a/std/cpp/_std/sys/db/Sqlite.hx +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -private class SqliteConnection implements Connection { - var c:Dynamic; - - public function new(file:String) { - c = _connect(file); - } - - public function close() { - _close(c); - } - - public function request(s:String):ResultSet { - try { - return new SqliteResultSet(_request(c, s)); - } catch (e:String) { - throw "Error while executing " + s + " (" + e + ")"; - } - } - - public function escape(s:String) { - return s.split("'").join("''"); - } - - public function quote(s:String) { - if (s.indexOf("\000") >= 0) { - var hexChars = new Array(); - for (i in 0...s.length) - hexChars.push(StringTools.hex(StringTools.fastCodeAt(s, i), 2)); - return "x'" + hexChars.join("") + "'"; - } - return "'" + s.split("'").join("''") + "'"; - } - - public function addValue(s:StringBuf, v:Dynamic) { - if (v == null) { - s.add(v); - } else if (Std.isOfType(v, Bool)) { - s.add(v ? 1 : 0); - } else { - var t:Int = untyped v.__GetType(); - if (t == 0xff) - s.add(v); - else if (t == 2) - s.add(untyped v.__GetInt()); - else - s.add(quote(Std.string(v))); - } - } - - public function lastInsertId():Int { - return _last_id(c); - } - - public function dbName() { - return "SQLite"; - } - - public function startTransaction() { - request("BEGIN TRANSACTION"); - } - - public function commit() { - request("COMMIT"); - } - - public function rollback() { - request("ROLLBACK"); - } - - @:native("_hx_sqlite_connect") - extern public static function _connect(filename:String):Dynamic; - - @:native("_hx_sqlite_request") - extern public static function _request(handle:Dynamic, req:String):Dynamic; - - @:native("_hx_sqlite_close") - extern public static function _close(handle:Dynamic):Void; - - @:native("_hx_sqlite_last_insert_id") - extern public static function _last_id(handle:Dynamic):Int; -} - -private class SqliteResultSet implements ResultSet { - public var length(get, null):Int; - public var nfields(get, null):Int; - - var r:Dynamic; - var cache:List; - - public function new(r:Dynamic) { - cache = new List(); - this.r = r; - hasNext(); // execute the request - } - - function get_length() { - if (nfields != 0) { - while (true) { - var c = result_next(r); - if (c == null) - break; - cache.add(c); - } - return cache.length; - } - return result_get_length(r); - } - - function get_nfields() { - return result_get_nfields(r); - } - - public function hasNext() { - var c = next(); - if (c == null) - return false; - cache.push(c); - return true; - } - - public function next():Dynamic { - var c = cache.pop(); - if (c != null) - return c; - return result_next(r); - } - - public function results():List { - var l = new List(); - while (true) { - var c = next(); - if (c == null) - break; - l.add(c); - } - return l; - } - - public function getResult(n:Int) { - return new String(result_get(r, n)); - } - - public function getIntResult(n:Int):Int { - return result_get_int(r, n); - } - - public function getFloatResult(n:Int):Float { - return result_get_float(r, n); - } - - public function getFieldsNames():Array { - throw new haxe.exceptions.NotImplementedException(); - } - - @:native("_hx_sqlite_result_next") - extern public static function result_next(handle:Dynamic):Dynamic; - - @:native("_hx_sqlite_result_get_length") - extern public static function result_get_length(handle:Dynamic):Int; - - @:native("_hx_sqlite_result_get_nfields") - extern public static function result_get_nfields(handle:Dynamic):Int; - - @:native("_hx_sqlite_result_get") - extern public static function result_get(handle:Dynamic, i:Int):String; - - @:native("_hx_sqlite_result_get_int") - extern public static function result_get_int(handle:Dynamic, i:Int):Int; - - @:native("_hx_sqlite_result_get_float") - extern public static function result_get_float(handle:Dynamic, i:Int):Float; -} - -@:buildXml('') -@:coreApi class Sqlite { - public static function open(file:String):Connection { - return new SqliteConnection(file); - } -} diff --git a/std/cpp/cppia/HostClasses.hx b/std/cpp/cppia/HostClasses.hx index b5674f85be6..8f40fa34d66 100644 --- a/std/cpp/cppia/HostClasses.hx +++ b/std/cpp/cppia/HostClasses.hx @@ -59,8 +59,6 @@ class HostClasses { "cpp.Finalizable", "Std", "StringBuf", - "sys.db.Mysql", - "sys.db.Sqlite", "sys.FileSystem", "sys.io.File", "sys.io.FileInput", @@ -180,10 +178,6 @@ class HostClasses { externs.set("haxe._Int32.___Int32", true); // Hidded in implementation classes // externs.set("sys.db.RecordType",true); - externs.set("sys.db._Sqlite.SqliteConnection", true); - externs.set("sys.db._Sqlite.SqliteResultSet", true); - externs.set("sys.db._Mysql.MysqlConnection", true); - externs.set("sys.db._Mysql.MysqlResultSet", true); externs.set("sys.net._Socket.SocketInput", true); externs.set("sys.net._Socket.SocketOutput", true); externs.set("sys.ssl._Socket.SocketInput", true); diff --git a/std/cs/_std/sys/db/Sqlite.hx b/std/cs/_std/sys/db/Sqlite.hx deleted file mode 100644 index 52d496bdf17..00000000000 --- a/std/cs/_std/sys/db/Sqlite.hx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -class Sqlite { - static var type:Class; - - public static function open(file:String):sys.db.Connection { - var cnxString = 'Data Source=$file'; - if (type == null) { - var t = null; - var assemblies = cs.system.AppDomain.CurrentDomain.GetAssemblies(); - for (i in 0...assemblies.Length) { - var a = assemblies[i]; - t = a.GetType('Mono.Data.Sqlite.SqliteConnection'); - if (t == null) - t = a.GetType('System.Data.SQLite.SQLiteConnection'); - if (t != null) { - break; - } - } - - if (t == null) { - var asm = cs.system.reflection.Assembly.Load('Mono.Data.Sqlite'); - t = asm.GetType('Mono.Data.Sqlite.SqliteConnection'); - } - - if (t != null) - type = cast cs.Lib.fromNativeType(t); - } - - if (type == null) { - throw "No ADO.NET SQLite provider was found!"; - } - var ret = Type.createInstance(type, [cnxString]); - ret.Open(); - return cs.db.AdoNet.create(ret, 'SQLite'); - } -} diff --git a/std/cs/db/AdoNet.hx b/std/cs/db/AdoNet.hx deleted file mode 100644 index 2c724c0c062..00000000000 --- a/std/cs/db/AdoNet.hx +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package cs.db; - -import sys.db.*; -import cs.system.data.*; - -class AdoNet { - public static function create(cnx:IDbConnection, dbName:String):Connection { - return new AdoConnection(cnx, dbName); - } -} - -private class AdoConnection implements Connection { - private static var ids = 0; - - private var id:Int; - - private var cnx:IDbConnection; - // escape handling - private var escapeRegex:EReg; - private var escapes:Array; - private var name:String; - private var command:IDbCommand; - private var transaction:IDbTransaction; - - public function new(cnx, name:String) { - this.id = cs.system.threading.Interlocked.Increment(ids); - this.cnx = cnx; - this.name = name; - this.escapes = []; - this.command = cnx.CreateCommand(); - this.escapeRegex = ~/@HX_ESCAPE(\d+)_(\d+)/; - } - - public function close():Void { - cnx.Close(); - } - - public function escape(s:String):String { - var param = command.CreateParameter(); - var name = "@HX_ESCAPE" + id + "_" + escapes.push(param) + ""; - param.ParameterName = name; - param.Value = s; - return name; - } - - public function quote(s:String):String { - var param = command.CreateParameter(); - var name = "@HX_ESCAPE" + id + "_" + escapes.push(param) + ""; - param.ParameterName = name; - param.Value = s; - return name; - } - - public function addValue(s:StringBuf, v:Dynamic) { - if (Std.isOfType(v, Date)) { - v = Std.string(v); - } else if (Std.isOfType(v, haxe.io.Bytes)) { - var bt:haxe.io.Bytes = v; - v = bt.getData(); - } - var param = command.CreateParameter(); - var name = "@HX_ESCAPE" + id + "_" + escapes.push(param) + ""; - param.ParameterName = name; - param.Value = v; - s.add(name); - } - - public function lastInsertId():Int { - var ret = cnx.CreateCommand(); - ret.CommandText = switch (name) { - case 'SQLite': - 'SELECT last_insert_rowid()'; - case _: - 'SELECT @@IDENTITY'; - } - ret.CommandType = CommandType.Text; - var r = cast ret.ExecuteScalar(); - ret.Dispose(); - - return r; - } - - public function dbName():String { - return name; - } - - public function startTransaction():Void { - if (this.transaction != null) - throw 'Transaction already active'; - this.transaction = cnx.BeginTransaction(); - } - - public function commit():Void { - if (this.transaction == null) - throw 'No transaction was initiated'; - this.transaction.Commit(); - } - - public function rollback():Void { - if (this.transaction == null) - throw 'No transaction was initiated'; - this.transaction.Rollback(); - } - - private static function getFirstStatement(s:String) { - var buf = new StringBuf(); - var hasData = false; - var chr = 0, i = 0; - inline function getch() - return chr = StringTools.fastCodeAt(s, i++); - while (!StringTools.isEof(getch())) { - inline function peek() { - var c = StringTools.fastCodeAt(s, i); - if (StringTools.isEof(c)) - break; - return c; - } - switch (chr) { - case ' '.code | '\t'.code | '\n'.code: - if (hasData) - return buf.toString(); - case '-'.code if (peek() == '-'.code): - if (hasData) - return buf.toString(); - while (!StringTools.isEof(getch())) { - if (chr == '\n'.code) - break; - } - case '#'.code: - if (hasData) - return buf.toString(); - while (!StringTools.isEof(getch())) { - if (chr == '\n'.code) - break; - } - case '/'.code if (peek() == '*'.code): - i++; - if (hasData) - return buf.toString(); - while (!StringTools.isEof(getch())) { - if (chr == '*'.code && peek() == '/'.code) { - i++; - break; - } - } - case _: - hasData = true; - buf.addChar(chr); - } - } - return buf.toString(); - } - - public function request(s:String):ResultSet { - var newst = new StringBuf(); - // cycle through the request string, adding any @HX_ESCAPE reference to the command - var ret:ResultSet = null; - var r = escapeRegex; - var myid = id + "", escapes = escapes, elen = escapes.length; - var cmd = this.command; - try { - while (r.match(s)) { - var id = r.matched(1); - #if debug - if (id != myid) - throw "Request quotes are only valid for one single request; They can't be cached."; - #end - - newst.add(r.matchedLeft()); - var eid = Std.parseInt(r.matched(2)); - #if debug - if (eid == null || eid > elen) - throw "Invalid request quote ID " + eid; - #end - cmd.Parameters.Add(escapes[eid - 1]); - newst.add(escapes[eid - 1].ParameterName); - s = r.matchedRight(); - } - newst.add(s); - - s = newst.toString(); - cmd.CommandText = s; - - var stmt = getFirstStatement(s).toLowerCase(); - if (stmt == 'select') { - ret = new AdoResultSet(cmd.ExecuteReader()); - } else { - cmd.ExecuteNonQuery(); - ret = EmptyResultSet.empty; - } - - if (escapes.length != 0) - this.escapes = []; - this.id = cs.system.threading.Interlocked.Increment(ids); - cmd.Dispose(); - this.command = cnx.CreateCommand(); - return ret; - } catch (e:Dynamic) { - if (escapes.length != 0) - this.escapes = []; - this.id = cs.system.threading.Interlocked.Increment(ids); - try { - cmd.Dispose(); - } catch (e:Dynamic) {} - this.command = cnx.CreateCommand(); - cs.Lib.rethrow(e); - } - return null; - } -} - -private class AdoResultSet implements ResultSet { - public var length(get, null):Int; - public var nfields(get, null):Int; - - private var reader:IDataReader; - private var didNext:Bool; - private var names:Array; - private var types:Array>; - - public function new(reader) { - this.reader = reader; - this.names = [for (i in 0...reader.FieldCount) reader.GetName(i)]; - this.types = [for (i in 0...names.length) cs.Lib.fromNativeType(reader.GetFieldType(i))]; - } - - private function get_length() { - return reader.Depth; - } - - private function get_nfields() { - return names.length; - } - - public function hasNext():Bool { - didNext = true; - return reader.Read(); - } - - public function next():Dynamic { - if (!didNext && !hasNext()) - return null; - didNext = false; - var ret = {}, names = names, types = types; - for (i in 0...names.length) { - var name = names[i], t = types[i], val:Dynamic = null; - if (reader.IsDBNull(i)) { - val = null; - } else if (t == cs.system.Single) { - val = reader.GetDouble(i); - } else if (t == cs.system.DateTime || t == cs.system.TimeSpan) { - var d = reader.GetDateTime(i); - if (d != null) - val = @:privateAccess Date.fromNative(d); - } else if (t == cs.system.DBNull) { - val = null; - } else if (t == cs.system.Byte) { - var v2:cs.StdTypes.UInt8 = reader.GetValue(i); - val = cast(v2, Int); - } else if (Std.string(t) == 'System.Byte[]') { - val = haxe.io.Bytes.ofData(reader.GetValue(i)); - } else { - val = reader.GetValue(i); - } - if (Std.isOfType(val, cs.system.DBNull)) - val = null; - Reflect.setField(ret, name, val); - } - return ret; - } - - public function results():List { - var l = new List(); - while (hasNext()) - l.add(next()); - return l; - } - - public function getResult(n:Int):String { - return reader.GetString(n); - } - - public function getIntResult(n:Int):Int { - return reader.GetInt32(n); - } - - public function getFloatResult(n:Int):Float { - return reader.GetDouble(n); - } - - public function getFieldsNames():Null> { - return names; - } -} - -private class EmptyResultSet implements ResultSet { - public static var empty = new EmptyResultSet(); - - public function new() {} - - public var length(get, null):Int; - public var nfields(get, null):Int; - - private function get_length() { - return 0; - } - - private function get_nfields() { - return 0; - } - - public function hasNext():Bool - return false; - - public function next():Dynamic - return null; - - public function results():List - return new List(); - - public function getResult(n:Int):String - return null; - - public function getIntResult(n:Int):Int - return 0; - - public function getFloatResult(n:Int):Float - return 0; - - public function getFieldsNames():Null> - return null; -} diff --git a/std/hl/_std/sys/db/Connection.hx b/std/hl/_std/sys/db/Connection.hx deleted file mode 100644 index d7331f5d5a4..00000000000 --- a/std/hl/_std/sys/db/Connection.hx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -interface Connection { - function request(s:String):ResultSet; - function close():Void; - function escape(s:String):String; - function quote(s:String):String; - function addValue(s:StringBuf, v:Dynamic):Void; - function lastInsertId():Int; - function dbName():String; - function startTransaction():Void; - function commit():Void; - function rollback():Void; -} diff --git a/std/hl/_std/sys/db/Mysql.hx b/std/hl/_std/sys/db/Mysql.hx deleted file mode 100644 index b3d9fd4962d..00000000000 --- a/std/hl/_std/sys/db/Mysql.hx +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -private class MysqlParams { - public var host:hl.Bytes; - public var user:hl.Bytes; - public var pass:hl.Bytes; - public var socket:hl.Bytes; - public var port:Int; - - public function new() {} -} - -private typedef ConnectionHandler = hl.Abstract<"mysql_cnx">; -private typedef ResultHandler = hl.Abstract<"mysql_result">; - -@:hlNative("mysql") -private class MysqlResultSet implements sys.db.ResultSet { - public var length(get, null):Int; - public var nfields(get, null):Int; - - private var r:ResultHandler; - private var cache:Dynamic; - - function new(r) { - this.r = r; - } - - private function get_length() { - return result_get_length(r); - } - - private function get_nfields() { - return result_get_nfields(r); - } - - public function hasNext() { - if (cache == null) - cache = next(); - return (cache != null); - } - - public function next():Dynamic { - var c = cache; - if (c != null) { - cache = null; - return c; - } - c = result_next(r); - return c; - } - - public function results():List { - var l = new List(); - while (hasNext()) - l.add(next()); - return l; - } - - public function getResult(n:Int) { - var v = result_get(r, n); - if (v == null) - return null; - return @:privateAccess String.fromUTF8(v); - } - - public function getIntResult(n:Int):Int { - return result_get_int(r, n); - } - - public function getFloatResult(n:Int):Float { - return result_get_float(r, n); - } - - public function getFieldsNames():Array { - var a = result_get_fields_names(r); - return [for (v in a) @:privateAccess String.fromUTF8(v)]; - } - - static function result_get_length(r:ResultHandler):Int { - return 0; - } - - static function result_get_nfields(r:ResultHandler):Int { - return 0; - } - - static function result_next(r:ResultHandler):Dynamic { - return null; - } - - static function result_get(r:ResultHandler, n:Int):hl.Bytes { - return null; - } - - static function result_get_int(r:ResultHandler, n:Int):Int { - return 0; - } - - static function result_get_float(r:ResultHandler, n:Int):Float { - return 0.; - } - - static function result_get_fields_names(r:ResultHandler):hl.NativeArray { - return null; - } -} - -@:hlNative("mysql") -private class MysqlConnection implements Connection { - var h:ConnectionHandler; - - function new(h) { - this.h = h; - } - - public function close() { - if (h != null) - close_wrap(h); - h = null; - } - - public function request(s:String) @:privateAccess { - var len = 0; - var b = s.bytes.utf16ToUtf8(0, len); - return new MysqlResultSet(request_wrap(h, b, len)); - } - - public function escape(s:String) @:privateAccess { - var len = 0; - var utf = s.bytes.utf16ToUtf8(0, len); - return String.fromUTF8(escape_wrap(h, utf, len)); - } - - public function quote(s:String) { - return "'" + escape(s) + "'"; - } - - public function addValue(s:StringBuf, v:Dynamic) { - if (v == null) { - s.add(null); - return; - } - var t = hl.Type.getDynamic(v).kind; - if (t == HI32 || t == HF64) - s.add(v); - else if (t == HBool) - s.addChar(if (v) "1".code else "0".code); - else { - s.addChar("'".code); - s.add(escape(Std.string(v))); - s.addChar("'".code); - } - } - - public function lastInsertId() { - return request("SELECT LAST_INSERT_ID()").getIntResult(0); - } - - public function dbName() { - return "MySQL"; - } - - public function startTransaction() { - request("START TRANSACTION"); - } - - public function commit() { - request("COMMIT"); - } - - public function rollback() { - request("ROLLBACK"); - } - - static function close_wrap(h:ConnectionHandler) {} - - static function connect_wrap(p:MysqlParams):ConnectionHandler { - return null; - } - - static function select_db_wrap(h:ConnectionHandler, db:hl.Bytes):Bool { - return false; - } - - @:hlNative("mysql", "request") - static function request_wrap(h:ConnectionHandler, rq:hl.Bytes, rqLen:Int):ResultHandler { - return null; - } - - @:hlNative("mysql", "escape") - static function escape_wrap(h:ConnectionHandler, str:hl.Bytes, len:Int):hl.Bytes { - return null; - } - - static function setConvFuns(fstring:Dynamic, fbytes:Dynamic, fdate:Dynamic, fjson:Dynamic) {}; -} - -class Mysql { - static var INIT_DONE = false; - - public static function connect(params:{ - host:String, - ?port:Int, - user:String, - pass:String, - ?socket:String, - ?database:String - }):sys.db.Connection@:privateAccess { - if (!INIT_DONE) { - INIT_DONE = true; - MysqlConnection.setConvFuns(function(v:hl.Bytes) return @:privateAccess String.fromUTF8(v), - function(v:hl.Bytes, len:Int) return new haxe.io.Bytes(v, len), function(t) return Date.fromTime(1000. * t), - function(v:hl.Bytes) return haxe.Json.parse(@:privateAccess String.fromUTF8(v))); - } - var p = new MysqlParams(); - p.host = params.host == null ? null : params.host.toUtf8(); - p.user = params.user.toUtf8(); - p.pass = params.pass.toUtf8(); - p.socket = params.socket == null ? null : params.socket.toUtf8(); - p.port = params.port == null ? 3306 : params.port; - var cnx = new MysqlConnection(MysqlConnection.connect_wrap(p)); - if (params.database != null && !MysqlConnection.select_db_wrap(cnx.h, params.database.toUtf8())) { - cnx.close(); - throw "Failed to select database " + params.database; - } - return cnx; - } -} diff --git a/std/hl/_std/sys/db/ResultSet.hx b/std/hl/_std/sys/db/ResultSet.hx deleted file mode 100644 index 49f689994e8..00000000000 --- a/std/hl/_std/sys/db/ResultSet.hx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -interface ResultSet { - var length(get, null):Int; - var nfields(get, null):Int; - - function hasNext():Bool; - function next():Dynamic; - function results():List; - function getResult(n:Int):String; - function getIntResult(n:Int):Int; - function getFloatResult(n:Int):Float; - function getFieldsNames():Null>; -} diff --git a/std/hl/_std/sys/db/Sqlite.hx b/std/hl/_std/sys/db/Sqlite.hx deleted file mode 100644 index 7c1fd32ea66..00000000000 --- a/std/hl/_std/sys/db/Sqlite.hx +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -import haxe.crypto.BaseCode; - -private typedef SqliteConnectionHandle = hl.Abstract<"sqlite_database">; -private typedef SqliteResultHandle = hl.Abstract<"sqlite_result">; - -@:hlNative("sqlite") -private class SqliteLib { - public static function connect(path:hl.Bytes):SqliteConnectionHandle { - return null; - } - - public static function close(c:SqliteConnectionHandle):Void {} - - public static function request(c:SqliteConnectionHandle, sql:hl.Bytes):SqliteResultHandle { - return null; - } - - public static function last_id(c:SqliteConnectionHandle):Int { - return 0; - } - - public static function result_next(c:SqliteResultHandle):hl.NativeArray { - return null; - } - - public static function result_get(c:SqliteResultHandle, n:Int):Null { - return null; - } - - public static function result_get_int(c:SqliteResultHandle, n:Int):Null { - return 0; - } - - public static function result_get_float(c:SqliteResultHandle, n:Int):Null { - return .0; - } - - public static function result_get_length(c:SqliteResultHandle):Null { - return 0; - } - - public static function result_get_nfields(c:SqliteResultHandle):Int { - return 0; - } - - public static function result_get_fields(c:SqliteResultHandle):hl.NativeArray { - return null; - } -} - -@:access(Sys) -@:access(String) -private class SqliteConnection implements Connection { - var c:SqliteConnectionHandle; - - public function new(file:String) { - c = SqliteLib.connect(file.bytes); - } - - public function close():Void { - SqliteLib.close(c); - } - - public function request(s:String):ResultSet { - try { - var r:SqliteResultHandle = SqliteLib.request(c, s.bytes); - - return new SqliteResultSet(r); - } catch (e:String) { - throw 'Error while executing $s ($e)'; - } - - return null; - } - - public function escape(s:String):String { - return s.split("'").join("''"); - } - - public function quote(s:String):String { - if (s.indexOf("\000") >= 0) - return "x'" + BaseCode.encode(s, "0123456789ABCDEF") + "'"; - - return "'" + s.split("'").join("''") + "'"; - } - - public function addValue(s:StringBuf, v:Dynamic):Void { - switch (Type.typeof(v)) { - case TNull, TInt: - s.add(v); - case TBool: - s.add(v ? 1 : 0); - case TClass(haxe.io.Bytes): - s.add("x'"); - s.add((v : haxe.io.Bytes).toHex()); - s.add("'"); - case _: - s.add(quote(Std.string(v))); - } - } - - public function lastInsertId():Int { - return SqliteLib.last_id(c); - } - - public function dbName():String { - return "SQLite"; - } - - public function startTransaction():Void { - request("BEGIN TRANSACTION"); - } - - public function commit():Void { - request("COMMIT"); - } - - public function rollback():Void { - request("ROLLBACK"); - } -} - -@:access(String) -private class SqliteResultSet implements ResultSet { - public var length(get, null):Int; - public var nfields(get, null):Int; - - var names:Array; - var cache:List; - - var r:SqliteResultHandle; - - public function new(r:SqliteResultHandle) { - cache = new List(); - this.r = r; - hasNext(); // execute the request - } - - function get_length():Int { - if (nfields != 0) { - while (true) { - var c = doNext(); - if (c == null) - break; - - cache.add(c); - } - - return cache.length; - } - - return SqliteLib.result_get_length(r); - } - - function get_nfields():Int { - return SqliteLib.result_get_nfields(r); - } - - public function hasNext():Bool { - var c = next(); - if (c == null) - return false; - - cache.push(c); - - return true; - } - - public function next():Dynamic { - var c = cache.pop(); - if (c != null) - return c; - - return doNext(); - } - - private function doNext():Dynamic { - var o:Dynamic = {}; - var a = SqliteLib.result_next(r); - if (a == null) - return null; - - var names = getFieldsNames(); - var i = 0; - var l = names.length; - while (i < l) { - var n:String = names[i]; - var v:Dynamic = a[i]; - switch (hl.Type.getDynamic(v).kind) { - case hl.Type.TypeKind.HArray: - var pair:hl.NativeArray = v; - var bytes:hl.Bytes = pair[0]; - var len:Int = pair[1]; - var data = new haxe.io.BytesData(bytes, len); - Reflect.setField(o, n, haxe.io.Bytes.ofData(data)); - - case hl.Type.TypeKind.HBytes: - Reflect.setField(o, n, String.fromUCS2(v)); - - default: - Reflect.setField(o, n, v); - } - i++; - } - return o; - } - - public function results():List { - var l = new List(); - while (true) { - var c = next(); - if (c == null) - break; - - l.add(c); - } - - return l; - } - - public function getResult(n:Int):String { - var bytes = SqliteLib.result_get(r, n); - if (bytes == null) - return null; - - return String.fromUCS2(bytes); - } - - public function getIntResult(n:Int):Int { - return SqliteLib.result_get_int(r, n); - } - - public function getFloatResult(n:Int):Float { - return SqliteLib.result_get_float(r, n); - } - - public function getFieldsNames():Array { - if (this.names != null) - return this.names; - - this.names = []; - var names = SqliteLib.result_get_fields(r); - var i = 0; - var l = names.length; - while (i < l) { - var name = String.fromUCS2(names[i]); - this.names.push(name); - i++; - } - - return this.names; - } -} - -@:coreApi class Sqlite { - public static function open(file:String):Connection { - return new SqliteConnection(file); - } -} diff --git a/std/java/_std/sys/db/Mysql.hx b/std/java/_std/sys/db/Mysql.hx deleted file mode 100644 index 6dfabe52e54..00000000000 --- a/std/java/_std/sys/db/Mysql.hx +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -class Mysql { - static var init = false; - - public static function connect(params:{ - host:String, - ?port:Int, - user:String, - pass:String, - ?socket:String, - ?database:String - }):sys.db.Connection { - if (!init) { - java.lang.Class.forName("com.mysql.jdbc.Driver"); - init = true; - } - var url = new StringBuf(); - url.add('jdbc:mysql:'); - if (params.socket != null) { - url.add(params.socket); - } else { - url.add('//'); - url.add(params.host); - if (params.port != null) - url.add(':${params.port}'); - } - if (params.database != null) { - url.add('/${params.database}'); - } - var cnx = java.sql.DriverManager.getConnection(url.toString(), params.user, params.pass); - return java.db.Jdbc.create(cnx); - } -} diff --git a/std/java/_std/sys/db/Sqlite.hx b/std/java/_std/sys/db/Sqlite.hx deleted file mode 100644 index 378f8190eb7..00000000000 --- a/std/java/_std/sys/db/Sqlite.hx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -class Sqlite { - static var init = false; - - public static function open(file:String):sys.db.Connection { - if (!init) { - try - java.lang.Class.forName("org.sqlite.JDBC") - catch (e:Dynamic) - throw e; - init = true; - } - try { - var cnx = java.sql.DriverManager.getConnection("jdbc:sqlite:" + file); - return java.db.Jdbc.create(cnx); - } catch (e:Dynamic) - throw e; - } -} diff --git a/std/java/db/Jdbc.hx b/std/java/db/Jdbc.hx deleted file mode 100644 index cc81e6535e4..00000000000 --- a/std/java/db/Jdbc.hx +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package java.db; - -import haxe.io.Bytes; -import java.sql.Types; -import java.util.concurrent.atomic.AtomicInteger; - -@:native('haxe.java.db.Jdbc') -class Jdbc { - public static function create(cnx:java.sql.Connection):sys.db.Connection { - return new JdbcConnection(cnx); - } -} - -@:native('haxe.java.db.JdbcConnection') -private class JdbcConnection implements sys.db.Connection { - private static var ids = new AtomicInteger(0); - - private var id:Int; - - private var cnx:java.sql.Connection; - private var _lastInsertId:Int; - // escape handling - private var escapeRegex:EReg; - private var escapes:Array; - - public function new(cnx) { - this.id = ids.getAndIncrement(); - this.cnx = cnx; - this.escapes = []; - this.escapeRegex = ~/@@HX_ESCAPE(\d+)_(\d+)@@/; - } - - public function close() { - try - this.cnx.close() - catch (e:Dynamic) - throw e; - } - - public function escape(s:String):String { - return "@@HX_ESCAPE" + id + "_" + escapes.push(s) + "@@"; - } - - public function quote(s:String):String { - return "@@HX_ESCAPE" + id + "_" + escapes.push(s) + "@@"; - } - - public function addValue(s:StringBuf, v:Dynamic) { - if (Std.isOfType(v, Date)) { - v = Std.string(v); - } else if (Std.isOfType(v, Bytes)) { - var bt:Bytes = v; - v = bt.getData(); - } - s.add("@@HX_ESCAPE"); - s.add(id); - s.add("_"); - s.add(escapes.push(v)); - s.add("@@"); - } - - public function lastInsertId():Int { - return _lastInsertId; - } - - public function dbName():String { - try { - var ret = cnx.getMetaData().getDriverName(); - var retc = ret.toLowerCase(); - if (retc.indexOf("mysql") != -1) - return "MySQL"; - else if (retc.indexOf("sqlite") != -1) - return "SQLite"; - return ret; - } catch (e:Dynamic) { - throw e; - } - } - - public function startTransaction() { - try { - cnx.setAutoCommit(false); - } catch (e:Dynamic) - throw e; - } - - public function commit() { - try { - cnx.commit(); - } catch (e:Dynamic) { - throw e; - } - } - - public function rollback() { - try - cnx.rollback() - catch (e:Dynamic) - throw e; - } - - public function request(s:String):sys.db.ResultSet { - var newst = new StringBuf(); - var sentArray = []; - - // cycle through the request string, adding any @@HX_ESCAPE@@ reference to the sentArray - var r = escapeRegex; - var myid = id + "", escapes = escapes, elen = escapes.length; - try { - while (r.match(s)) { - var id = r.matched(1); - if (id != myid) - throw "Request quotes are only valid for one single request; They can't be cached."; - - newst.add(r.matchedLeft()); - var eid = Std.parseInt(r.matched(2)); - if (eid == null || eid > elen) - throw "Invalid request quote ID " + eid; - sentArray.push(escapes[eid - 1]); - newst.add("?"); - s = r.matchedRight(); - } - newst.add(s); - var stmt = cnx.prepareStatement(newst.toString(), - #if jvm java.sql.Statement.RETURN_GENERATED_KEYS #else java.sql.Statement.Statement_Statics.RETURN_GENERATED_KEYS #end); - for (i in 0...sentArray.length) { - stmt.setObject(i + 1, sentArray[i]); - } - - var ret = null, dbName = dbName(); - if (stmt.execute()) { - // is a result set - var rs = stmt.getResultSet(); - ret = new JdbcResultSet(rs, dbName, stmt.getMetaData()); - } else { - // is an update - var affected = stmt.getUpdateCount(); - if (affected == 1) { - var autogen = stmt.getGeneratedKeys(); - if (autogen.next()) { - this._lastInsertId = autogen.getInt(1); - } - } - ret = new JdbcResultSet(null, dbName, null); - } - - if (escapes.length != 0) - escapes = []; - this.id = ids.getAndIncrement(); - return ret; - } catch (e:Dynamic) { - if (escapes.length != 0) - escapes = []; - this.id = ids.getAndIncrement(); - throw e; - } - } -} - -@:native('haxe.java.db.JdbcResultSet') -private class JdbcResultSet implements sys.db.ResultSet { - @:isVar public var length(get, null):Int; - public var nfields(get, null):Int; - - private var rs:java.sql.ResultSet; - private var names:Array; - private var types:java.NativeArray; - private var dbName:String; - private var didNext:Bool; - - public function new(rs, dbName, meta:java.sql.ResultSetMetaData) { - this.dbName = dbName; - this.rs = rs; - if (meta != null) { - try { - var count = meta.getColumnCount(); - var names = [], types = new NativeArray(count); - for (i in 0...count) { - names.push(meta.getColumnName(i + 1)); - types[i] = meta.getColumnType(i + 1); - } - this.types = types; - this.names = names; - } catch (e:Dynamic) - throw e; - } - } - - private function get_length():Int { - if (length == 0) { - try { - var cur = rs.getRow(); - rs.last(); - this.length = rs.getRow(); - rs.absolute(cur); - } catch (e:Dynamic) - throw e; - } - return length; - } - - private function get_nfields():Int { - return names == null ? 0 : names.length; - } - - public function hasNext():Bool { - try { - didNext = true; - return rs != null && rs.next(); - } catch (e:Dynamic) { - return throw e; - } - } - - public function next():Dynamic { - try { - if (rs == null) - return null; - if (didNext) { - didNext = false; - } else { - if (!rs.next()) { - return null; - } - } - var ret = {}, names = names, types = types; - for (i in 0...names.length) { - var name = names[i], t = types[i], val:Dynamic = null; - if (t == Types.FLOAT) { - val = rs.getDouble(i + 1); - } else if (t == Types.DATE || t == Types.TIME) { - if (dbName == "SQLite") { - var str = rs.getString(i + 1); - if (str != null) { - var d:Date = Date.fromString(str); - val = d; - } - } else { - var d:java.sql.Date = rs.getDate(i + 1); - if (d != null) - val = Date.fromTime(cast d.getTime()); - } - } else if (t == Types.LONGVARBINARY || t == Types.VARBINARY || t == Types.BINARY || t == Types.BLOB) { - var b = rs.getBytes(i + 1); - if (b != null) - val = Bytes.ofData(b); - } else { - val = rs.getObject(i + 1); - } - Reflect.setField(ret, name, val); - } - return ret; - } catch (e:Dynamic) - throw e; - } - - public function results():List { - var l = new List(); - if (rs == null) - return l; - - try { - while (hasNext()) - l.add(next()); - } catch (e:Dynamic) - throw e; - return l; - } - - public function getResult(n:Int):String { - try { - return rs.getString(n); - } catch (e:Dynamic) - throw e; - } - - public function getIntResult(n:Int):Int { - try { - return rs.getInt(n); - } catch (e:Dynamic) { - return throw e; - }; - } - - public function getFloatResult(n:Int):Float { - try { - return rs.getFloat(n); - } catch (e:Dynamic) { - return throw e; - }; - } - - public function getFieldsNames():Null> { - return this.names; - } -} diff --git a/std/neko/Web.hx b/std/neko/Web.hx deleted file mode 100644 index 5623895b32e..00000000000 --- a/std/neko/Web.hx +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package neko; - -import haxe.ds.List; - -/** - This class is used for accessing the local Web server and the current - client request and information. -**/ -class Web { - /** - Returns the GET and POST parameters. - **/ - public static function getParams() { - var p = _get_params(); - var h = new haxe.ds.StringMap(); - var k = ""; - while (p != null) { - untyped k.__s = p[0]; - h.set(k, new String(p[1])); - p = untyped p[2]; - } - return h; - } - - /** - Returns an Array of Strings built using GET / POST values. - If the URL contains the parameters `[a[]=foo;a[]=hello;a[5]=bar;a[3]=baz]` then - `neko.Web.getParamValues("a")` will return `["foo","hello",null,"baz",null,"bar"]` - **/ - public static function getParamValues(param:String):Array { - var reg = new EReg("^" + param + "(\\[|%5B)([0-9]*?)(\\]|%5D)=(.*?)$", ""); - var res = new Array(); - var explore = function(data:String) { - if (data == null || data.length == 0) - return; - for (part in data.split("&")) { - if (reg.match(part)) { - var idx = reg.matched(2); - var val = StringTools.urlDecode(reg.matched(4)); - if (idx == "") - res.push(val); - else - res[Std.parseInt(idx)] = val; - } - } - } - explore(StringTools.replace(getParamsString(), ";", "&")); - explore(getPostData()); - if (res.length == 0) - return null; - return res; - } - - /** - Returns the local server host name. - **/ - public static function getHostName() { - return new String(_get_host_name()); - } - - /** - Surprisingly returns the client IP address. - **/ - public static function getClientIP() { - return new String(_get_client_ip()); - } - - /** - Returns the original request URL (before any server internal redirections) - **/ - public static function getURI() { - return new String(_get_uri()); - } - - /** - Tell the client to redirect to the given url ("Location" header) - **/ - public static function redirect(url:String) { - _cgi_redirect(untyped url.__s); - } - - /** - Set an output header value. If some data have been printed, the headers have - already been sent so this will raise an exception. - **/ - public static function setHeader(h:String, v:String) { - _cgi_set_header(untyped h.__s, untyped v.__s); - } - - /** - Set the HTTP return code. Same remark as setHeader. - **/ - public static function setReturnCode(r:Int) { - _set_return_code(r); - } - - /** - Retrieve a client header value sent with the request. - **/ - public static function getClientHeader(k:String) { - var v = _get_client_header(untyped k.__s); - if (v == null) - return null; - return new String(v); - } - - /** - Retrieve all the client headers. - **/ - public static function getClientHeaders() { - var v = _get_client_headers(); - var a = new List(); - while (v != null) { - a.add({header: new String(v[0]), value: new String(v[1])}); - v = cast v[2]; - } - return a; - } - - /** - Returns all the GET parameters String. - **/ - public static function getParamsString() { - var p = _get_params_string(); - return if (p == null) "" else new String(p); - } - - /** - Returns all the POST data. POST Data is always parsed as - being `application/x-www-form-urlencoded` and is stored into - the getParams hashtable. POST Data is maximimized to 256K - unless the content type is `multipart/form-data`. In that - case, you will have to use `getMultipart` or `parseMultipart` - methods. - **/ - public static function getPostData() { - var v = _get_post_data(); - if (v == null) - return null; - return new String(v); - } - - /** - Returns an hashtable of all Cookies sent by the client. - Modifying the hashtable will not modify the cookie, use `setCookie` instead. - **/ - public static function getCookies():Map { - var p = _get_cookies(); - var h = new haxe.ds.StringMap(); - var k = ""; - while (p != null) { - untyped k.__s = p[0]; - h.set(k, new String(p[1])); - p = untyped p[2]; - } - return h; - } - - /** - Set a Cookie value in the HTTP headers. Same remark as `setHeader`. - **/ - public static function setCookie(key:String, value:String, ?expire:Date, ?domain:String, ?path:String, ?secure:Bool, ?httpOnly:Bool) { - var buf = new StringBuf(); - buf.add(value); - if (expire != null) - addPair(buf, "expires=", DateTools.format(expire, "%a, %d-%b-%Y %H:%M:%S GMT")); - addPair(buf, "domain=", domain); - addPair(buf, "path=", path); - if (secure) - addPair(buf, "secure", ""); - if (httpOnly) - addPair(buf, "HttpOnly", ""); - var v = buf.toString(); - _set_cookie(untyped key.__s, untyped v.__s); - } - - static function addPair(buf:StringBuf, name:String, value:String) { - if (value == null) - return; - buf.add("; "); - buf.add(name); - buf.add(value); - } - - /** - Returns an object with the authorization sent by the client (Basic scheme only). - **/ - public static function getAuthorization():{user:String, pass:String} { - var h = getClientHeader("Authorization"); - var reg = ~/^Basic ([^=]+)=*$/; - if (h != null && reg.match(h)) { - var val = reg.matched(1); - untyped val = new String(_base_decode(val.__s, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".__s)); - var a = val.split(":"); - if (a.length != 2) { - throw "Unable to decode authorization."; - } - return {user: a[0], pass: a[1]}; - } - return null; - } - - /** - Get the current script directory in the local filesystem. - **/ - public static function getCwd() { - return new String(_get_cwd()); - } - - /** - Set the main entry point function used to handle requests. - Setting it back to null will disable code caching. - **/ - public static function cacheModule(f:Void->Void) { - _set_main(f); - } - - /** - Get the multipart parameters as an hashtable. The data - cannot exceed the maximum size specified. - **/ - public static function getMultipart(maxSize:Int):Map { - var h = new haxe.ds.StringMap(); - var buf:haxe.io.BytesBuffer = null; - var curname = null; - parseMultipart(function(p, _) { - if (curname != null) - h.set(curname, neko.Lib.stringReference(buf.getBytes())); - curname = p; - buf = new haxe.io.BytesBuffer(); - maxSize -= p.length; - if (maxSize < 0) - throw "Maximum size reached"; - }, function(str, pos, len) { - maxSize -= len; - if (maxSize < 0) - throw "Maximum size reached"; - buf.addBytes(str, pos, len); - }); - if (curname != null) - h.set(curname, neko.Lib.stringReference(buf.getBytes())); - return h; - } - - /** - Parse the multipart data. Call `onPart` when a new part is found - with the part name and the filename if present - and `onData` when some part data is read. You can this way - directly save the data on hard drive in the case of a file upload. - **/ - public static function parseMultipart(onPart:String->String->Void, onData:haxe.io.Bytes->Int->Int->Void):Void { - _parse_multipart(function(p, f) { - onPart(new String(p), if (f == null) null else new String(f)); - }, function(buf, pos, len) { - onData(untyped new haxe.io.Bytes(__dollar__ssize(buf), buf), pos, len); - }); - } - - /** - Flush the data sent to the client. By default on Apache, outgoing data is buffered so - this can be useful for displaying some long operation progress. - **/ - public static function flush():Void { - _flush(); - } - - /** - Get the HTTP method used by the client. This API requires Neko 1.7.1+. - **/ - public static function getMethod():String { - return new String(_get_http_method()); - } - - /** - Write a message into the web server log file. This API requires Neko 1.7.1+. - **/ - public static function logMessage(msg:String) { - _log_message(untyped msg.__s); - } - - public static var isModNeko(default, null):Bool; - public static var isTora(default, null):Bool; - - static var _set_main:Dynamic; - static var _get_host_name:Dynamic; - static var _get_client_ip:Dynamic; - static var _get_uri:Dynamic; - static var _cgi_redirect:Dynamic; - static var _cgi_set_header:Dynamic; - static var _set_return_code:Dynamic; - static var _get_client_header:Dynamic; - static var _get_params_string:Dynamic; - static var _get_post_data:Dynamic; - static var _get_params:Dynamic; - static var _get_cookies:Dynamic; - static var _set_cookie:Dynamic; - static var _get_cwd:Dynamic; - static var _parse_multipart:Dynamic; - static var _flush:Dynamic; - static var _get_client_headers:Dynamic; - static var _get_http_method:Dynamic; - static var _base_decode = Lib.load("std", "base_decode", 2); - static var _log_message:Dynamic; - - static function __init__() { - var get_env = Lib.load("std", "get_env", 1); - var ver = untyped get_env("MOD_NEKO".__s); - untyped isModNeko = (ver != null); - if (isModNeko) { - var lib = "mod_neko" + if (ver == untyped "1".__s) "" else ver; - _set_main = Lib.load(lib, "cgi_set_main", 1); - _get_host_name = Lib.load(lib, "get_host_name", 0); - _get_client_ip = Lib.load(lib, "get_client_ip", 0); - _get_uri = Lib.load(lib, "get_uri", 0); - _cgi_redirect = Lib.load(lib, "redirect", 1); - _cgi_set_header = Lib.load(lib, "set_header", 2); - _set_return_code = Lib.load(lib, "set_return_code", 1); - _get_client_header = Lib.load(lib, "get_client_header", 1); - _get_params_string = Lib.load(lib, "get_params_string", 0); - _get_post_data = Lib.load(lib, "get_post_data", 0); - _get_params = Lib.load(lib, "get_params", 0); - _get_cookies = Lib.load(lib, "get_cookies", 0); - _set_cookie = Lib.load(lib, "set_cookie", 2); - _get_cwd = Lib.load(lib, "cgi_get_cwd", 0); - _get_http_method = Lib.loadLazy(lib, "get_http_method", 0); - _parse_multipart = Lib.loadLazy(lib, "parse_multipart_data", 2); - _flush = Lib.loadLazy(lib, "cgi_flush", 0); - _get_client_headers = Lib.loadLazy(lib, "get_client_headers", 0); - _log_message = Lib.loadLazy(lib, "log_message", 1); - isTora = try Lib.load(lib, "tora_infos", 0) != null catch (e:Dynamic) false; - } else { - var a0 = untyped __dollar__loader.args[0]; - if (a0 != null) - a0 = new String(a0); - _set_main = function(f) {}; - _get_host_name = function() { - return untyped "localhost".__s; - }; - _get_client_ip = function() { - return untyped "127.0.0.1".__s; - }; - _get_uri = function() { - return untyped (if (a0 == null) "/" else a0).__s; - }; - _cgi_redirect = function(v) { - Lib.print("Location: " + v + "\n"); - }; - _cgi_set_header = function(h, v) {}; - _set_return_code = function(i) {}; - _get_client_header = function(h) { - return null; - }; - _get_client_headers = function() { - return null; - }; - _get_params_string = function() { - return untyped (if (a0 == null) "" else a0).__s; - }; - _get_post_data = function() { - return null; - }; - _get_params = function() { - var l = null; - if (a0 == null) - return null; - for (p in a0.split(";")) { - var k = p.split("="); - if (k.length == 2) - l = untyped [k[0].__s, k[1].__s, l]; - } - return l; - }; - _get_cookies = function() { - return null; - } - _set_cookie = function(k, v) {}; - _get_cwd = Lib.load("std", "get_cwd", 0); - _get_http_method = function() return untyped "GET".__s; - _parse_multipart = function(a, b) { - throw "Not supported"; - }; - _flush = function() {}; - _log_message = function(s) {}; - isTora = false; - } - } -} diff --git a/std/neko/_std/sys/db/Mysql.hx b/std/neko/_std/sys/db/Mysql.hx deleted file mode 100644 index 7856feb6ca1..00000000000 --- a/std/neko/_std/sys/db/Mysql.hx +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -private class D { - static function load(fun, args):Dynamic { - return neko.Lib.load(lib, fun, args); - } - - static var lib = try { - neko.Lib.load("mysql5", "connect", 1); - "mysql5"; - } catch (e:Dynamic) "mysql"; - public static var connect = load("connect", 1); - public static var select_db = load("select_db", 2); - public static var request = load("request", 2); - public static var close = load("close", 1); - public static var escape = load("escape", 2); - public static var set_conv_funs = load("set_conv_funs", 4); - public static var result_get_length = load("result_get_length", 1); - public static var result_get_nfields = load("result_get_nfields", 1); - public static var result_next = load("result_next", 1); - public static var result_get = load("result_get", 2); - public static var result_get_int = load("result_get_int", 2); - public static var result_get_float = load("result_get_float", 2); - public static var result_fields_names = neko.Lib.loadLazy(lib, "result_get_fields_names", 1); -} - -private class MysqlResultSet implements sys.db.ResultSet { - public var length(get, null):Int; - public var nfields(get, null):Int; - - private var __r:Dynamic; - private var cache:Dynamic; - - public function new(r) { - __r = r; - } - - private function get_length() { - return D.result_get_length(__r); - } - - private function get_nfields() { - return D.result_get_nfields(__r); - } - - public function hasNext() { - if (cache == null) - cache = next(); - return (cache != null); - } - - public function next():Dynamic { - var c = cache; - if (c != null) { - cache = null; - return c; - } - c = D.result_next(__r); - return c; - } - - public function results():List { - var l = new List(); - while (hasNext()) - l.add(next()); - return l; - } - - public function getResult(n:Int) { - return new String(D.result_get(__r, n)); - } - - public function getIntResult(n:Int):Int { - return D.result_get_int(__r, n); - } - - public function getFloatResult(n:Int):Float { - return D.result_get_float(__r, n); - } - - public function getFieldsNames():Array { - var a = D.result_fields_names(__r); - untyped { - var i = 0; - var l = __dollar__asize(a); - while (i < l) { - a[i] = new String(a[i]); - i += 1; - } - a = Array.new1(cast a, l); - } - return a; - } -} - -private class MysqlConnection implements sys.db.Connection { - private var __c:Dynamic; - - public function new(c) { - __c = c; - D.set_conv_funs(c, function(s) return new String(s), function(d) return untyped Date.new1(d), function(b) return haxe.io.Bytes.ofData(b)); - } - - public function request(s:String):sys.db.ResultSet { - try { - var r = D.request(this.__c, untyped s.__s); - return new MysqlResultSet(r); - } catch (e:Dynamic) { - untyped if (__dollar__typeof(e) == __dollar__tobject && __dollar__typeof(e.msg) == __dollar__tstring) - e = e.msg; - untyped __dollar__rethrow(e); - return null; - } - } - - public function close() { - D.close(__c); - } - - public function escape(s:String) { - return new String(D.escape(__c, untyped s.__s)); - } - - public function quote(s:String) { - return "'" + escape(s) + "'"; - } - - public function addValue(s:StringBuf, v:Dynamic) { - var t = untyped __dollar__typeof(v); - if (untyped (t == __dollar__tint || t == __dollar__tnull)) - s.add(v); - else if (untyped t == __dollar__tbool) - s.addChar(if (v) "1".code else "0".code); - else { - s.addChar("'".code); - s.add(escape(Std.string(v))); - s.addChar("'".code); - } - } - - public function lastInsertId() { - return request("SELECT LAST_INSERT_ID()").getIntResult(0); - } - - public function dbName() { - return "MySQL"; - } - - public function startTransaction() { - request("START TRANSACTION"); - } - - public function commit() { - request("COMMIT"); - } - - public function rollback() { - request("ROLLBACK"); - } - - private static var __use_date = Date; -} - -@:coreApi class Mysql { - public static function connect(params:{ - host:String, - ?port:Int, - user:String, - pass:String, - ?socket:String, - ?database:String - }):sys.db.Connection { - var o = untyped { - host: params.host.__s, - port: if (params.port == null) 3306 else params.port, - user: params.user.__s, - pass: params.pass.__s, - socket: if (params.socket == null) null else params.socket.__s - }; - var c = D.connect(o); - if (params.database != null) { - try { - D.select_db(c, untyped params.database.__s); - } catch (e:Dynamic) { - D.close(c); - neko.Lib.rethrow(e); - } - } - return new MysqlConnection(c); - } -} diff --git a/std/neko/_std/sys/db/Sqlite.hx b/std/neko/_std/sys/db/Sqlite.hx deleted file mode 100644 index fd247a30ef0..00000000000 --- a/std/neko/_std/sys/db/Sqlite.hx +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -private class SqliteConnection implements Connection { - var c:Dynamic; - - public function new(file:String) { - c = _connect(untyped file.__s); - } - - public function close() { - _close(c); - } - - public function request(s:String):ResultSet { - try { - return new SqliteResultSet(_request(c, untyped s.__s)); - } catch (e:String) { - throw "Error while executing " + s + " (" + e + ")"; - } - } - - public function escape(s:String) { - return s.split("'").join("''"); - } - - public function quote(s:String) { - if (s.indexOf("\000") >= 0) - return "x'" + new String(untyped _encode(s.__s, "0123456789ABCDEF".__s)) + "'"; - return "'" + s.split("'").join("''") + "'"; - } - - public function addValue(s:StringBuf, v:Dynamic) { - var t = untyped __dollar__typeof(v); - if (untyped (t == __dollar__tint || t == __dollar__tnull)) - s.add(v); - else if (untyped t == __dollar__tbool) - s.add(if (v) 1 else 0); - else - s.add(quote(Std.string(v))); - } - - public function lastInsertId() { - return _last_id(c); - } - - public function dbName() { - return "SQLite"; - } - - public function startTransaction() { - request("BEGIN TRANSACTION"); - } - - public function commit() { - request("COMMIT"); - } - - public function rollback() { - request("ROLLBACK"); - } - - static var _encode = neko.Lib.load("std", "base_encode", 2); - static var _connect = neko.Lib.load("sqlite", "connect", 1); - static var _close = neko.Lib.load("sqlite", "close", 1); - static var _request = neko.Lib.load("sqlite", "request", 2); - static var _last_id = neko.Lib.load("sqlite", "last_insert_id", 1); -} - -private class SqliteResultSet implements ResultSet { - public var length(get, null):Int; - public var nfields(get, null):Int; - - var r:Dynamic; - var cache:List; - - public function new(r) { - cache = new List(); - this.r = r; - hasNext(); // execute the request - } - - function get_length() { - if (nfields != 0) { - while (true) { - var c = doNext(); - if (c == null) - break; - cache.add(c); - } - return cache.length; - } - return result_get_length(r); - } - - function get_nfields() { - return result_get_nfields(r); - } - - public function hasNext() { - var c = next(); - if (c == null) - return false; - cache.push(c); - return true; - } - - public function next():Dynamic { - var c = cache.pop(); - if (c != null) - return c; - return doNext(); - } - - private function doNext():Dynamic { - var c = result_next(r); - if (c == null) - return null; - untyped { - var f = __dollar__objfields(c); - var i = 0; - var l = __dollar__asize(f); - while (i < l) { - var v = __dollar__objget(c, f[i]); - if (__dollar__typeof(v) == __dollar__tstring) - __dollar__objset(c, f[i], new String(v)); - i = i + 1; - } - } - return c; - } - - public function results():List { - var l = new List(); - while (true) { - var c = next(); - if (c == null) - break; - l.add(c); - } - return l; - } - - public function getResult(n:Int) { - return new String(result_get(r, n)); - } - - public function getIntResult(n:Int):Int { - return result_get_int(r, n); - } - - public function getFloatResult(n:Int):Float { - return result_get_float(r, n); - } - - public function getFieldsNames():Array { - if(hasNext()) { - return switch cache.first() { - case null: null; - case row: Reflect.fields(row); - } - } - return null; - } - - static var result_next = neko.Lib.load("sqlite", "result_next", 1); - static var result_get_length = neko.Lib.load("sqlite", "result_get_length", 1); - static var result_get_nfields = neko.Lib.load("sqlite", "result_get_nfields", 1); - static var result_get = neko.Lib.load("sqlite", "result_get", 2); - static var result_get_int = neko.Lib.load("sqlite", "result_get_int", 2); - static var result_get_float = neko.Lib.load("sqlite", "result_get_float", 2); -} - -@:coreApi class Sqlite { - public static function open(file:String):Connection { - return new SqliteConnection(file); - } -} diff --git a/std/php/Web.hx b/std/php/Web.hx deleted file mode 100644 index d546d7bde13..00000000000 --- a/std/php/Web.hx +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php; - -import haxe.io.Bytes; -import haxe.ds.Map; -import php.Syntax.*; -import php.Global.*; -import php.SuperGlobal.*; - -/** - This class is used for accessing the local Web server and the current - client request and information. -**/ -@:deprecated('php.Web is deprecated and will be removed from standard library. See php.SuperGlobal and php.Global for alternatives.') -class Web { - /** - Returns the GET and POST parameters. - **/ - public static function getParams():Map { - #if force_std_separator - var h = Lib.hashOfAssociativeArray(_POST); - var params = getParamsString(); - if (params == "") - return h; - for (p in ~/[;&]/g.split(params)) { - var a = p.split("="); - var n = a.shift(); - h.set(StringTools.urlDecode(n), StringTools.urlDecode(a.join("="))); - } - return h; - #else - return Lib.hashOfAssociativeArray(array_merge(_GET, _POST)); - #end - } - - /** - Returns an Array of Strings built using GET / POST values. - If you have in your URL the parameters `a[]=foo;a[]=hello;a[5]=bar;a[3]=baz` then - `php.Web.getParamValues("a")` will return `["foo","hello",null,"baz",null,"bar"]`. - **/ - public static function getParamValues(param:String):Array { - var reg = new EReg("^" + param + "(\\[|%5B)([0-9]*?)(\\]|%5D)=(.*?)$", ""); - var res = new Array(); - var explore = function(data:String) { - if (data == null || Global.strlen(data) == 0) - return; - for (part in data.split("&")) { - if (reg.match(part)) { - var idx = reg.matched(2); - var val = StringTools.urlDecode(reg.matched(4)); - if (idx == "") - res.push(val); - else - res[Std.parseInt(idx)] = val; - } - } - } - explore(StringTools.replace(getParamsString(), ";", "&")); - explore(getPostData()); - - if (res.length == 0) { - var post:haxe.ds.StringMap = Lib.hashOfAssociativeArray(_POST); - var data = post.get(param); - if (is_array(data)) { - foreach(data, function(key:Int, value:String) { - res[key] = value; - }); - } - } - - if (res.length == 0) - return null; - return res; - } - - /** - Returns the local server host name. - **/ - public static inline function getHostName():String { - return _SERVER['SERVER_NAME']; - } - - /** - Surprisingly returns the client IP address. - **/ - public static inline function getClientIP():String { - return _SERVER['REMOTE_ADDR']; - } - - /** - Returns the original request URL (before any server internal redirections). - **/ - public static function getURI():String { - var s:String = _SERVER['REQUEST_URI']; - return s.split("?")[0]; - } - - /** - Tell the client to redirect to the given url ("Location" header). - **/ - public static function redirect(url:String) { - header("Location: " + url); - } - - /** - Set an output header value. If some data have been printed, the headers have - already been sent so this will raise an exception. - **/ - public static inline function setHeader(h:String, v:String) { - header('$h: $v'); - } - - /** - Set the HTTP return code. Same remark as `php.Web.setHeader()`. - See status code explanation here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html - **/ - public static function setReturnCode(r:Int) { - var code:String; - switch (r) { - case 100: - code = "100 Continue"; - case 101: - code = "101 Switching Protocols"; - case 200: - code = "200 OK"; - case 201: - code = "201 Created"; - case 202: - code = "202 Accepted"; - case 203: - code = "203 Non-Authoritative Information"; - case 204: - code = "204 No Content"; - case 205: - code = "205 Reset Content"; - case 206: - code = "206 Partial Content"; - case 300: - code = "300 Multiple Choices"; - case 301: - code = "301 Moved Permanently"; - case 302: - code = "302 Found"; - case 303: - code = "303 See Other"; - case 304: - code = "304 Not Modified"; - case 305: - code = "305 Use Proxy"; - case 307: - code = "307 Temporary Redirect"; - case 400: - code = "400 Bad Request"; - case 401: - code = "401 Unauthorized"; - case 402: - code = "402 Payment Required"; - case 403: - code = "403 Forbidden"; - case 404: - code = "404 Not Found"; - case 405: - code = "405 Method Not Allowed"; - case 406: - code = "406 Not Acceptable"; - case 407: - code = "407 Proxy Authentication Required"; - case 408: - code = "408 Request Timeout"; - case 409: - code = "409 Conflict"; - case 410: - code = "410 Gone"; - case 411: - code = "411 Length Required"; - case 412: - code = "412 Precondition Failed"; - case 413: - code = "413 Request Entity Too Large"; - case 414: - code = "414 Request-URI Too Long"; - case 415: - code = "415 Unsupported Media Type"; - case 416: - code = "416 Requested Range Not Satisfiable"; - case 417: - code = "417 Expectation Failed"; - case 500: - code = "500 Internal Server Error"; - case 501: - code = "501 Not Implemented"; - case 502: - code = "502 Bad Gateway"; - case 503: - code = "503 Service Unavailable"; - case 504: - code = "504 Gateway Timeout"; - case 505: - code = "505 HTTP Version Not Supported"; - default: - code = Std.string(r); - } - header("HTTP/1.1 " + code, true, r); - } - - /** - Retrieve a client header value sent with the request. - **/ - public static function getClientHeader(k:String):String { - return loadClientHeaders().get(str_replace('-', '_', strtoupper(k))); - } - - private static var _clientHeaders:Map; - - /** - Based on https://github.com/ralouphie/getallheaders - **/ - static function loadClientHeaders():Map { - if (_clientHeaders != null) - return _clientHeaders; - - _clientHeaders = new Map(); - - if (function_exists('getallheaders')) { - foreach(getallheaders(), function(key:String, value:Dynamic) { - _clientHeaders.set(str_replace('-', '_', strtoupper(key)), Std.string(value)); - }); - return _clientHeaders; - } - - var copyServer = Syntax.assocDecl({ - CONTENT_TYPE: 'Content-Type', - CONTENT_LENGTH: 'Content-Length', - CONTENT_MD5: 'Content-Md5' - }); - foreach(_SERVER, function(key:String, value:Dynamic) { - if ((substr(key, 0, 5) : String) == 'HTTP_') { - key = substr(key, 5); - if (!isset(copyServer[key]) || !isset(_SERVER[key])) { - _clientHeaders[key] = Std.string(value); - } - } else if (isset(copyServer[key])) { - _clientHeaders[key] = Std.string(value); - } - }); - if (!_clientHeaders.exists('AUTHORIZATION')) { - if (isset(_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { - _clientHeaders['AUTHORIZATION'] = Std.string(_SERVER['REDIRECT_HTTP_AUTHORIZATION']); - } else if (isset(_SERVER['PHP_AUTH_USER'])) { - var basic_pass = isset(_SERVER['PHP_AUTH_PW']) ? Std.string(_SERVER['PHP_AUTH_PW']) : ''; - _clientHeaders['AUTHORIZATION'] = 'Basic ' + base64_encode(_SERVER['PHP_AUTH_USER'] + ':' + basic_pass); - } else if (isset(_SERVER['PHP_AUTH_DIGEST'])) { - _clientHeaders['AUTHORIZATION'] = Std.string(_SERVER['PHP_AUTH_DIGEST']); - } - } - - return _clientHeaders; - } - - /** - Retrieve all the client headers. - **/ - public static function getClientHeaders():List<{value:String, header:String}> { - var headers = loadClientHeaders(); - var result = new List(); - for (key in headers.keys()) { - result.push({value: headers.get(key), header: key}); - } - return result; - } - - /** - Retrieve all the client headers as `haxe.ds.Map`. - **/ - public static function getClientHeadersMap():Map { - return loadClientHeaders().copy(); - } - - /** - Returns all the GET parameters `String` - **/ - public static function getParamsString():String { - if (isset(_SERVER['QUERY_STRING'])) - return _SERVER['QUERY_STRING']; - else - return ""; - } - - /** - Returns all the POST data. POST Data is always parsed as - being application/x-www-form-urlencoded and is stored into - the getParams hashtable. POST Data is maximimized to 256K - unless the content type is multipart/form-data. In that - case, you will have to use `php.Web.getMultipart()` or - `php.Web.parseMultipart()` methods. - **/ - public static function getPostData():Null { - var h = fopen("php://input", "r"); - var bsize = 8192; - var max = 32; - var data:String = null; - var counter = 0; - while (!feof(h) && counter < max) { - data = Syntax.concat(data, fread(h, bsize)); - counter++; - } - fclose(h); - return data; - } - - /** - Returns an hashtable of all Cookies sent by the client. - Modifying the hashtable will not modify the cookie, use `php.Web.setCookie()` - instead. - **/ - public static function getCookies():Map { - return Lib.hashOfAssociativeArray(_COOKIE); - } - - /** - Set a Cookie value in the HTTP headers. Same remark as `php.Web.setHeader()`. - **/ - public static function setCookie(key:String, value:String, ?expire:Date, ?domain:String, ?path:String, ?secure:Bool, ?httpOnly:Bool) { - var t = expire == null ? 0 : Std.int(expire.getTime() / 1000.0); - if (path == null) - path = '/'; - if (domain == null) - domain = ''; - if (secure == null) - secure = false; - if (httpOnly == null) - httpOnly = false; - setcookie(key, value, t, path, domain, secure, httpOnly); - } - - /** - Returns an object with the authorization sent by the client (Basic scheme only). - **/ - public static function getAuthorization():{user:String, pass:String} { - if (!isset(_SERVER['PHP_AUTH_USER'])) - return null; - return {user: _SERVER['PHP_AUTH_USER'], pass: _SERVER['PHP_AUTH_PW']}; - } - - /** - Get the current script directory in the local filesystem. - **/ - public static inline function getCwd():String { - return dirname(_SERVER['SCRIPT_FILENAME']) + "/"; - } - - /** - Get the multipart parameters as an hashtable. The data - cannot exceed the maximum size specified. - **/ - public static function getMultipart(maxSize:Int):Map { - var h = new haxe.ds.StringMap(); - var buf:StringBuf = null; - var curname = null; - parseMultipart(function(p, _) { - if (curname != null) - h.set(curname, buf.toString()); - curname = p; - buf = new StringBuf(); - maxSize -= Global.strlen(p); - if (maxSize < 0) - throw "Maximum size reached"; - }, function(str, pos, len) { - maxSize -= len; - if (maxSize < 0) - throw "Maximum size reached"; - buf.addSub(str.toString(), pos, len); - }); - if (curname != null) - h.set(curname, buf.toString()); - return h; - } - - /** - Parse the multipart data. Call `onPart` when a new part is found - with the part name and the filename if present - and `onData` when some part data is readed. You can this way - directly save the data on hard drive in the case of a file upload. - **/ - public static function parseMultipart(onPart:String->String->Void, onData:Bytes->Int->Int->Void):Void { - Syntax.foreach(_POST, function(key:String, value:Dynamic) { - onPart(key, ""); - onData(Bytes.ofString(value), 0, strlen(value)); - }); - - if (!isset(_FILES)) - return; - Syntax.foreach(_FILES, function(part:String, data:NativeAssocArray) { - function handleFile(tmp:String, file:String, err:Int) { - var fileUploaded = true; - if (err > 0) { - switch (err) { - case 1: - throw "The uploaded file exceeds the max size of " + ini_get('upload_max_filesize'); - case 2: - throw "The uploaded file exceeds the max file size directive specified in the HTML form (max is" + ini_get('post_max_size') + ")"; - case 3: - throw "The uploaded file was only partially uploaded"; - case 4: - fileUploaded = false; // No file was uploaded - case 6: - throw "Missing a temporary folder"; - case 7: - throw "Failed to write file to disk"; - case 8: - throw "File upload stopped by extension"; - } - } - if (fileUploaded) { - onPart(part, file); - if ("" != file) { - var h = fopen(tmp, "r"); - var bsize = 8192; - while (!feof(h)) { - var buf:String = fread(h, bsize); - var size:Int = strlen(buf); - onData(Bytes.ofString(buf), 0, size); - } - fclose(h); - } - } - } - if (is_array(data['name'])) { - for (index in array_keys(data['name'])) { - handleFile(data['tmp_name'][index], data['name'][index], data['error'][index]); - }; - } else { - handleFile(data['tmp_name'], data['name'], data['error']); - } - }); - } - - /** - Flush the data sent to the client. By default on Apache, outgoing data is buffered so - this can be useful for displaying some long operation progress. - **/ - public static inline function flush():Void { - Global.flush(); - } - - /** - Get the HTTP method used by the client. - **/ - public static function getMethod():String { - if (isset(_SERVER['REQUEST_METHOD'])) - return _SERVER['REQUEST_METHOD']; - else - return null; - } - - public static var isModNeko(default, null):Bool; - - static function __init__() { - isModNeko = !Lib.isCli(); - } -} diff --git a/std/php/_std/sys/db/Mysql.hx b/std/php/_std/sys/db/Mysql.hx deleted file mode 100644 index 7321b588049..00000000000 --- a/std/php/_std/sys/db/Mysql.hx +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -import php.*; -import sys.db.*; -import php.db.*; -import php.db.Mysqli_result; - -@:coreApi class Mysql { - public static function connect(params:{ - host:String, - ?port:Int, - user:String, - pass:String, - ?socket:String, - ?database:String - }):Connection { - return new MysqlConnection(params); - } -} - -private class MysqlConnection implements Connection { - var db:Mysqli; - - public function new(params:{ - host:String, - ?port:Int, - user:String, - pass:String, - ?socket:String, - ?database:String - }):Void { - if (params.port == null) - params.port = Std.parseInt(Global.ini_get('mysqli.default_port')); - if (params.socket == null) - params.socket = Global.ini_get('mysqli.default_socket'); - if (params.database == null) - params.database = ""; - - db = new Mysqli(params.host, params.user, params.pass, params.database, params.port, params.socket); - } - - public function request(s:String):ResultSet { - var result = db.query(s); - if (result == false) - throw 'Failed to perform db query: ' + db.error; - if (result == true) { - return new WriteMysqlResultSet(db.affected_rows); - } - - return new MysqlResultSet(result); - } - - public function close():Void { - db.close(); - } - - public function escape(s:String):String { - return db.escape_string(s); - } - - public function quote(s:String):String { - if (s.indexOf("\000") >= 0) - return "x'" + Global.bin2hex(s) + "'"; - return "'" + db.escape_string(s) + "'"; - } - - public function addValue(s:StringBuf, v:Dynamic):Void { - if (Global.is_int(v) || Global.is_null(v)) { - s.add(v); - } else if (Global.is_bool(v)) { - s.add(v ? 1 : 0); - } else { - s.add(quote(Std.string(v))); - } - } - - public function lastInsertId():Int { - return db.insert_id; - } - - public function dbName():String { - return 'MySQL'; - } - - public function startTransaction():Void { - var success = db.begin_transaction(); - if (!success) - throw 'Failed to start transaction: ' + db.error; - } - - public function commit():Void { - var success = db.commit(); - if (!success) - throw 'Failed to commit transaction: ' + db.error; - } - - public function rollback():Void { - var success = db.rollback(); - if (!success) - throw 'Failed to rollback transaction: ' + db.error; - } -} - -private class MysqlResultSet implements ResultSet { - static var hxAnonClassName = Boot.getHxAnon().phpClassName; - - public var length(get, null):Int; - public var nfields(get, null):Int; - - var result:Mysqli_result; - var fetchedRow:NativeAssocArray; - var fieldsInfo:NativeAssocArray; - - public function new(result:Mysqli_result) { - this.result = result; - } - - public function hasNext():Bool { - if (fetchedRow == null) - fetchNext(); - return fetchedRow != null; - } - - public function next():Dynamic { - if (fetchedRow == null) - fetchNext(); - return withdrawFetched(); - } - - public function results():List { - var list = new List(); - - result.data_seek(0); - var row = result.fetch_object(hxAnonClassName); - while (row != null) { - row = correctObjectTypes(row); - list.add(row); - row = result.fetch_object(hxAnonClassName); - } - - return list; - } - - public function getResult(n:Int):String { - if (fetchedRow == null) - fetchNext(); - return Global.array_values(fetchedRow)[n]; - } - - public function getIntResult(n:Int):Int { - return Syntax.int(getResult(n)); - } - - public function getFloatResult(n:Int):Float { - return Syntax.float(getResult(n)); - } - - public function getFieldsNames():Null> { - var fields = result.fetch_fields(); - return [for (field in fields) field.name]; - } - - function fetchNext() { - var row = result.fetch_assoc(); - if (row != null) - fetchedRow = correctArrayTypes(row); - } - - function withdrawFetched():Dynamic { - if (fetchedRow == null) - return null; - var row = fetchedRow; - fetchedRow = null; - return Boot.createAnon(row); - } - - function correctArrayTypes(row:NativeAssocArray):NativeAssocArray { - var fieldsInfo = getFieldsInfo(); - Syntax.foreach(row, function(field:String, value:String) { - row[field] = correctType(value, fieldsInfo[field].type); - }); - return cast row; - } - - function correctObjectTypes(row:{}):{} { - var fieldsInfo = getFieldsInfo(); - Syntax.foreach(row, function(field:String, value:String) { - value = correctType(value, fieldsInfo[field].type); - Syntax.setField(row, field, value); - }); - return row; - } - - inline function getFieldsInfo():NativeAssocArray { - if (fieldsInfo == null) { - fieldsInfo = cast Syntax.arrayDecl(); - Syntax.foreach(result.fetch_fields(), function(_, info) { - fieldsInfo[info.name] = info; - }); - } - return fieldsInfo; - } - - function correctType(value:String, type:Int):Scalar { - if (value == null) - return null; - if (type == Const.MYSQLI_TYPE_BIT || type == Const.MYSQLI_TYPE_TINY || type == Const.MYSQLI_TYPE_SHORT || type == Const.MYSQLI_TYPE_LONG - || type == Const.MYSQLI_TYPE_INT24 || type == Const.MYSQLI_TYPE_CHAR) { - return Syntax.int(value); - } - if (type == Const.MYSQLI_TYPE_DECIMAL - || type == Const.MYSQLI_TYPE_NEWDECIMAL - || type == Const.MYSQLI_TYPE_FLOAT - || type == Const.MYSQLI_TYPE_DOUBLE) { - return Syntax.float(value); - } - return value; - } - - function get_length() - return result.num_rows; - - function get_nfields() - return result.field_count; -} - -private class WriteMysqlResultSet extends MysqlResultSet { - var affectedRows:Int = 0; - - public function new(affectedRows:Int) { - super(null); - this.affectedRows = affectedRows; - } - - override public function hasNext():Bool { - return false; - } - - override function fetchNext() {} - - override function get_length() - return affectedRows; - - override function get_nfields() - return 0; -} diff --git a/std/php/_std/sys/db/Sqlite.hx b/std/php/_std/sys/db/Sqlite.hx deleted file mode 100644 index c8be8d8b2c5..00000000000 --- a/std/php/_std/sys/db/Sqlite.hx +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -import php.*; -import php.Global.*; -import php.db.*; -import sys.db.*; - -@:coreApi class Sqlite { - public static function open(file:String):Connection { - return new SQLiteConnection(file); - } -} - -private class SQLiteConnection implements Connection { - var db:SQLite3; - - public function new(file:String) { - db = new SQLite3(file); - db.enableExceptions(true); - } - - public function request(s:String):ResultSet { - var result = db.query(s); - return new SQLiteResultSet(result); - } - - public function close():Void { - db.close(); - } - - public function escape(s:String):String { - return SQLite3.escapeString(s); - } - - public function quote(s:String):String { - if (s.indexOf("\000") >= 0) - return "x'" + Global.bin2hex(s) + "'"; - return "'" + SQLite3.escapeString(s) + "'"; - } - - public function addValue(s:StringBuf, v:Dynamic):Void { - if (Global.is_int(v) || Global.is_null(v)) { - s.add(v); - } else if (Global.is_bool(v)) { - s.add(v ? 1 : 0); - } else { - s.add(quote(Std.string(v))); - } - } - - public function lastInsertId():Int { - return Syntax.int(db.lastInsertRowID()); - } - - public function dbName():String { - return 'SQLite'; - } - - public function startTransaction():Void { - db.query('BEGIN TRANSACTION'); - } - - public function commit():Void { - db.query('COMMIT'); - } - - public function rollback():Void { - db.query('ROLLBACK'); - } -} - -private class SQLiteResultSet implements ResultSet { - public var length(get, null):Int; - public var nfields(get, null):Int; - - var cache = new NativeIndexedArray<{}>(); - var result:SQLite3Result; - var resultIsDepleted = false; - var fieldsInfo:NativeAssocArray; - - public function new(result:SQLite3Result) { - this.result = result; - } - - public function hasNext():Bool { - return switch next() { - case null: false; - case row: - array_unshift(cache, row); - row; - } - } - - public function next():Dynamic { - return switch array_shift(cache) { - case null: fetchNext(); - case row: row; - } - } - - function fetchNext():Null<{}> { - return resultIsDepleted ? null : switch result.fetchArray(Const.SQLITE3_ASSOC) { - case false: - resultIsDepleted = true; - result.finalize(); - null; - case row: - Boot.createAnon(correctArrayTypes(row)); - } - } - - public function cacheAll():NativeIndexedArray<{}> { - var row = fetchNext(); - while(row != null) { - cache.push(row); - row = fetchNext(); - } - return cache; - } - - public function results():List { - var list = new List(); - for(row in cacheAll()) { - list.add(row); - } - return list; - } - - function getColumn(n:Int):Any { - return array_values(Syntax.array(current()))[n]; - } - - public function getResult(n:Int):String { - return Syntax.string(getColumn(n)); - } - - public function getIntResult(n:Int):Int { - return Syntax.int(getColumn(n)); - } - - public function getFloatResult(n:Int):Float { - return Syntax.float(getColumn(n)); - } - - public function getFieldsNames():Null> { - var fieldsInfo = getFieldsInfo(); - return Global.array_keys(fieldsInfo); - } - - function current():Null<{}> { - return switch reset(cache) { - case false: - switch next() { - case null: null; - case row: - cache.push(row); - row; - } - case row: row; - } - } - - function correctArrayTypes(row:NativeAssocArray):NativeAssocArray { - var fieldsInfo = getFieldsInfo(); - Syntax.foreach(row, function(field:String, value:String) { - row[field] = correctType(value, fieldsInfo[field]); - }); - return cast row; - } - - inline function getFieldsInfo():NativeAssocArray { - if (fieldsInfo == null) { - fieldsInfo = cast Syntax.arrayDecl(); - for (i in 0...nfields) { - fieldsInfo[result.columnName(i)] = result.columnType(i); - } - } - return fieldsInfo; - } - - function correctType(value:String, type:Int):Scalar { - if (value == null) - return null; - if (type == Const.SQLITE3_INTEGER) - return Syntax.int(value); - if (type == Const.SQLITE3_FLOAT) - return Syntax.float(value); - return value; - } - - function get_length():Int - return count(cacheAll()); - - function get_nfields():Int - return result.numColumns(); -} diff --git a/std/php/db/Mysqli.hx b/std/php/db/Mysqli.hx deleted file mode 100644 index 85bcb8f9c58..00000000000 --- a/std/php/db/Mysqli.hx +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php.db; - -import haxe.extern.*; -import php.*; -import haxe.Constraints.Function; - -/** - @see http://php.net/manual/en/class.mysqli.php -**/ -@:native('Mysqli') -extern class Mysqli { - var affected_rows(default, null):Int; - var client_info(default, null):String; - var client_version(default, null):Int; - var connect_errno(default, null):Int; - var connect_error(default, null):String; - var errno(default, null):Int; - var error_list(default, null):NativeAssocArray; - var error(default, null):String; - var field_count(default, null):Int; - var host_info(default, null):String; - var protocol_version(default, null):String; - var server_info(default, null):String; - var server_version(default, null):Int; - var info(default, null):String; - var insert_id(default, null):EitherType; - var sqlstate(default, null):String; - var thread_id(default, null):Int; - var warning_count(default, null):Int; - - static function poll(read:Ref, error:Ref, reject:Ref, sec:Int, ?usec:Int):Int; - - function new(?host:String, ?username:String, ?passwd:String, dbname:String = "", ?port:Int, ?socket:String):Void; - function autocommit(mode:Bool):Bool; - function begin_transaction(?flags:Int, ?name:String):Bool; - function change_user(user:String, password:String, database:String):Bool; - function character_set_name():String; - function close():Bool; - function commit(?flags:Int, ?name:String):Bool; - function debug(message:String):Bool; - function dump_debug_info():Bool; - function get_charset():{ - charset:String, - collation:String, - dir:String, - min_length:Int, - number:Int, - state:Int - }; - function get_client_info():String; - function get_connection_stats():Bool; - function get_warnings():Mysqli_warning; - function init():Mysqli; - function kill(processid:Int):Bool; - function more_results():Bool; - function multi_query(query:String):Bool; - function next_result():Bool; - function options(option:Int, value:Scalar):Bool; - function ping():Bool; - function prepare(query:String):Mysqli_stmt; - function query(query:String, ?resultmode:Int):EitherType; - function real_connect(?host:String, ?username:String, ?passwd:String, ?dbname:String, ?port:Int, ?socket:String, ?flags:Int):Bool; - function escape_string(escapestr:String):String; - function real_query(query:String):Bool; - function reap_async_query():Mysqli_result; - function refresh(options:Int):Bool; - function rollback(?flags:Int, ?name:String):Bool; - function rpl_query_type(query:String):Int; - function select_db(dbname:String):Bool; - function send_query(query:String):Bool; - function set_charset(charset:String):Bool; - function set_local_infile_handler(read_func:Function):Bool; - function ssl_set(key:String, cert:String, ca:String, capath:String, cipher:String):Bool; - function stat():String; - function stmt_init():Mysqli_stmt; - function store_result(?option:Int):Mysqli_result; - function use_result():Mysqli_result; -} diff --git a/std/php/db/Mysqli_driver.hx b/std/php/db/Mysqli_driver.hx deleted file mode 100644 index 8293f41a4f3..00000000000 --- a/std/php/db/Mysqli_driver.hx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php.db; - -import php.NativeArray; - -@:native('Mysqli_driver') -extern class Mysqli_driver { - var client_info(default, null):String; - var client_version(default, null):String; - var driver_version(default, null):String; - var embedded(default, null):String; - var reconnect(default, null):Bool; - var report_mode(default, null):Int; - - function embedded_server_end():Void; - function embedded_server_start(start:Bool, arguments:NativeArray, groups:NativeArray):Bool; -} diff --git a/std/php/db/Mysqli_result.hx b/std/php/db/Mysqli_result.hx deleted file mode 100644 index f56e5952758..00000000000 --- a/std/php/db/Mysqli_result.hx +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php.db; - -import php.*; -import haxe.extern.*; - -/** - @see http://php.net/manual/en/class.mysqli-result.php -**/ -@:native('Myslqi_result') -extern class Mysqli_result implements Traversable { - var current_field(default, null):Int; - var field_count(default, null):Int; - var lengths(default, null):EitherType>; - var num_rows(default, null):Int; - - function data_seek(offset:Int):Bool; - function fetch_all(?resulttype:Int):NativeArray; - function fetch_array(?resulttype:Int):NativeArray; - function fetch_assoc():NativeAssocArray; - function fetch_field_direct(fieldnr:Int):MysqliFieldInfo; - function fetch_field():MysqliFieldInfo; - function fetch_fields():NativeIndexedArray; - function fetch_object(?class_name:String = "stdClass", ?params:NativeArray):{}; - function fetch_row():NativeIndexedArray; - function field_seek(fieldnr:Int):Bool; - function free():Void; -} - -typedef MysqliFieldInfo = { - name:String, - orgname:String, - table:String, - orgtable:String, - max_length:Int, - length:Int, - charsetnr:Int, - flags:Int, - type:Int, - decimals:Int -} diff --git a/std/php/db/Mysqli_stmt.hx b/std/php/db/Mysqli_stmt.hx deleted file mode 100644 index 5942aad372b..00000000000 --- a/std/php/db/Mysqli_stmt.hx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php.db; - -import haxe.extern.*; -import php.*; - -@:native('Mysqli_stmt') -extern class Mysqli_stmt { - var affected_rows(default, null):Int; - var errno(default, null):Int; - var error_list(default, null):NativeArray; - var error(default, null):String; - var field_count(default, null):Int; - var insert_id(default, null):Int; - var num_rows(default, null):Int; - var param_count(default, null):Int; - var sqlstate(default, null):String; - - function new(link:Mysqli, ?query:String):Void; - function attr_get(attr:Int):Int; - function attr_set(attr:Int, mode:Int):Bool; - function bind_param(types:String, var1:Ref, args:Rest>):Bool; - function bind_result(var1:Ref, args:Rest>):Bool; - function close():Bool; - function data_seek(offset:Int):Void; - function execute():Bool; - function fetch():Bool; - function free_result():Void; - function get_result():Mysqli_result; - function get_warnings(stmt:Mysqli_stmt):{}; - function prepare(query:String):Bool; - function reset():Bool; - function result_metadata():Mysqli_result; - function send_long_data(param_nr:Int, data:String):Bool; - function store_result():Bool; -} diff --git a/std/php/db/Mysqli_warning.hx b/std/php/db/Mysqli_warning.hx deleted file mode 100644 index 1f373d50b67..00000000000 --- a/std/php/db/Mysqli_warning.hx +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php.db; - -@:native('Mysqli_warning') -extern class Mysqli_warning { - var message(default, null):String; - var sqlstate(default, null):Dynamic; - var errno(default, null):Int; - - function next():Void; -} diff --git a/std/php/db/PDO.hx b/std/php/db/PDO.hx deleted file mode 100644 index 08158063865..00000000000 --- a/std/php/db/PDO.hx +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php.db; - -import php.*; - -@:native('PDO') -extern class PDO { - @:phpClassConst static final PARAM_BOOL:Int; - @:phpClassConst static final PARAM_NULL:Int; - @:phpClassConst static final PARAM_INT:Int; - @:phpClassConst static final PARAM_STR:Int; - @:phpClassConst static final PARAM_LOB:Int; - @:phpClassConst static final PARAM_STMT:Int; - @:phpClassConst static final PARAM_INPUT_OUTPUT:Int; - @:phpClassConst static final FETCH_LAZY:Int; - @:phpClassConst static final FETCH_ASSOC:Int; - @:phpClassConst static final FETCH_NAMED:Int; - @:phpClassConst static final FETCH_NUM:Int; - @:phpClassConst static final FETCH_BOTH:Int; - @:phpClassConst static final FETCH_OBJ:Int; - @:phpClassConst static final FETCH_BOUND:Int; - @:phpClassConst static final FETCH_COLUMN:Int; - @:phpClassConst static final FETCH_CLASS:Int; - @:phpClassConst static final FETCH_INTO:Int; - @:phpClassConst static final FETCH_FUNC:Int; - @:phpClassConst static final FETCH_GROUP:Int; - @:phpClassConst static final FETCH_UNIQUE:Int; - @:phpClassConst static final FETCH_KEY_PAIR:Int; - @:phpClassConst static final FETCH_CLASSTYPE:Int; - @:phpClassConst static final FETCH_SERIALIZE:Int; - @:phpClassConst static final FETCH_PROPS_LATE:Int; - @:phpClassConst static final ATTR_AUTOCOMMIT:Int; - @:phpClassConst static final ATTR_PREFETCH:Int; - @:phpClassConst static final ATTR_TIMEOUT:Int; - @:phpClassConst static final ATTR_ERRMODE:Int; - @:phpClassConst static final ATTR_SERVER_VERSION:Int; - @:phpClassConst static final ATTR_CLIENT_VERSION:Int; - @:phpClassConst static final ATTR_SERVER_INFO:Int; - @:phpClassConst static final ATTR_CONNECTION_STATUS:Int; - @:phpClassConst static final ATTR_CASE:Int; - @:phpClassConst static final ATTR_CURSOR_NAME:Int; - @:phpClassConst static final ATTR_CURSOR:Int; - @:phpClassConst static final ATTR_DRIVER_NAME:Int; - @:phpClassConst static final ATTR_ORACLE_NULLS:Int; - @:phpClassConst static final ATTR_PERSISTENT:Int; - @:phpClassConst static final ATTR_STATEMENT_CLASS:Int; - @:phpClassConst static final ATTR_DEFAULT_FETCH_MODE:Int; - @:phpClassConst static final ATTR_FETCH_TABLE_NAMES:Int; - @:phpClassConst static final ATTR_STRINGIFY_FETCHES:Int; - @:phpClassConst static final ATTR_EMULATE_PREPARES:Int; - @:phpClassConst static final ERRMODE_SILENT:Int; - @:phpClassConst static final ERRMODE_WARNING:Int; - @:phpClassConst static final ERRMODE_EXCEPTION:Int; - @:phpClassConst static final CASE_NATURAL:Int; - @:phpClassConst static final CASE_LOWER:Int; - @:phpClassConst static final CASE_UPPER:Int; - @:phpClassConst static final NULL_NATURAL:Int; - @:phpClassConst static final FETCH_ORI_PRIOR:Int; - @:phpClassConst static final FETCH_ORI_FIRST:Int; - @:phpClassConst static final FETCH_ORI_LAST:Int; - @:phpClassConst static final FETCH_ORI_ABS:Int; - @:phpClassConst static final FETCH_ORI_REL:Int; - @:phpClassConst static final CURSOR_FWDONLY:Int; - @:phpClassConst static final CURSOR_SCROLL:Int; - @:phpClassConst static final ERR_NONE:String; - @:phpClassConst static final PARAM_EVT_ALLOC:Int; - @:phpClassConst static final PARAM_EVT_FREE:Int; - @:phpClassConst static final PARAM_EVT_EXEC_PRE:Int; - @:phpClassConst static final PARAM_EVT_EXEC_POST:Int; - @:phpClassConst static final PARAM_EVT_FETCH_PRE:Int; - @:phpClassConst static final PARAM_EVT_FETCH_POST:Int; - @:phpClassConst static final PARAM_EVT_NORMALIZE:Int; - - function new(dns:String, ?username:String, ?password:String, ?options:NativeArray):Void; - function beginTransaction():Bool; - function commit():Bool; - function errorCode():Dynamic; - function errorInfo():NativeArray; - function exec(statement:String):Int; - function getAttribute(attribute:Int):Dynamic; - static function getAvailableDrivers():NativeIndexedArray; - function lastInsertId(?name:String):String; - function prepare(statement:String, ?driver_options:NativeArray):PDOStatement; - function query(statement:String, ?mode:Int):PDOStatement; - function quote(String:String, ?parameter_type:Int = 2):String; - function rollBack():Bool; - function setAttribute(attribute:Int, value:Dynamic):Bool; -} diff --git a/std/php/db/PDOException.hx b/std/php/db/PDOException.hx deleted file mode 100644 index a3a72cb3d8b..00000000000 --- a/std/php/db/PDOException.hx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php.db; - -import php.RuntimeException; - -@:native('PDOException') -extern class PDOException extends RuntimeException { - var errorInfo:NativeArray; -} diff --git a/std/php/db/PDOStatement.hx b/std/php/db/PDOStatement.hx deleted file mode 100644 index b720387dab1..00000000000 --- a/std/php/db/PDOStatement.hx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php.db; - -import php.*; - -@:native('PDOStatement') -extern class PDOStatement { - function bindColumn(column:Dynamic, param:Dynamic, ?type:Int, ?maxlen:Int, ?driverdata:Dynamic):Bool; - function bindParam(parameter:Dynamic, variable:Dynamic, ?data_type:Int, ?length:Int, ?driver_options:Dynamic):Bool; - function bindValue(parameter:Dynamic, value:Dynamic, ?data_type:Int):Bool; - function closeCursor():Bool; - function columnCount():Int; - function debugDumpParams():Bool; - function errorCode():String; - function errorInfo():NativeArray; - function execute(?input_parameters:NativeArray):Bool; - function fetch(?fetch_style:Int = 4, ?cursor_orientation:Int = 0, ?cursor_offset:Int = 0):Dynamic; - function fetchAll(?fetch_style:Int, ?fetch_argument:Dynamic, ?ctor_args:NativeArray):NativeArray; - function fetchColumn(?column_number:Int = 0):String; - function fetchObject(?class_name:String, ?ctor_args:NativeArray):Dynamic; - function getAttribute(attribute:Int):Dynamic; - function getColumnMeta(column:Int):NativeArray; - function nextRowset():Bool; - function rowCount():Int; - function setAttribute(attribute:Int, value:Dynamic):Bool; - function setFetchMode(mode:Int, ?fetch:Dynamic, ?ctorargs:NativeArray):Bool; -} diff --git a/std/php/db/SQLite3.hx b/std/php/db/SQLite3.hx deleted file mode 100644 index c775b053503..00000000000 --- a/std/php/db/SQLite3.hx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php.db; - -import haxe.Constraints; -import php.*; -import haxe.extern.EitherType; - -@:native('SQLite3') -extern class SQLite3 { - static function version():NativeArray; - static function escapeString(value:String):String; - function busyTimeout(msecs:Int):Bool; - function changes():Int; - function close():Bool; - function new(filename:String, ?flags:Int, encryption_key:String = null):Void; - function createAggregate(name:String, step_callback:Function, final_callback:Function, argument_count:Int = -1):Bool; - function createCollation(name:String, callback:Function):Bool; - function createFunction(name:String, callback:Function, argument_count:Int = -1):Bool; - function enableExceptions(enableExceptions:Bool = false):Bool; - function exec(query:String):Bool; - function lastErrorCode():Int; - function lastErrorMsg():String; - function lastInsertRowID():Int; - function loadExtension(shared_library:String):Bool; - function open(filename:String, ?flags:Int, encryption_key:String = null):Void; - function prepare(query:String):SQLite3Stmt; - function query(query:String):EitherType; - function querySingle(query:String, entire_row:Bool = false):Dynamic; -} diff --git a/std/php/db/SQLite3Result.hx b/std/php/db/SQLite3Result.hx deleted file mode 100644 index ea65802a6a8..00000000000 --- a/std/php/db/SQLite3Result.hx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php.db; - -import php.*; -import haxe.extern.EitherType; - -@:native('SQLite3Result') -extern class SQLite3Result { - function columnName(column_number:Int):String; - function columnType(column_number:Int):Int; - function fetchArray(?mode:Int):EitherType>; - function finalize():Bool; - function numColumns():Int; - function reset():Bool; -} diff --git a/std/php/db/SQLite3Stmt.hx b/std/php/db/SQLite3Stmt.hx deleted file mode 100644 index f3d13a98aac..00000000000 --- a/std/php/db/SQLite3Stmt.hx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package php.db; - -import php.*; -import haxe.extern.EitherType; - -@:native('SQLite3Stmt') -extern class SQLite3Stmt { - function bindParam(sql_param:EitherType, param:Ref, ?type:Int):Bool; - function bindValue(sql_param:EitherType, value:Dynamic, ?type:Int):Bool; - function clear():Bool; - function close():Bool; - function execute():SQLite3Result; - function paramCount():Int; - function readOnly():Bool; - function reset():Bool; -} diff --git a/std/sys/db/Connection.hx b/std/sys/db/Connection.hx deleted file mode 100644 index d7331f5d5a4..00000000000 --- a/std/sys/db/Connection.hx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -interface Connection { - function request(s:String):ResultSet; - function close():Void; - function escape(s:String):String; - function quote(s:String):String; - function addValue(s:StringBuf, v:Dynamic):Void; - function lastInsertId():Int; - function dbName():String; - function startTransaction():Void; - function commit():Void; - function rollback():Void; -} diff --git a/std/sys/db/Mysql.hx b/std/sys/db/Mysql.hx deleted file mode 100644 index ce673424e50..00000000000 --- a/std/sys/db/Mysql.hx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -class Mysql { - public static function connect(params:{ - host:String, - ?port:Int, - user:String, - pass:String, - ?socket:String, - ?database:String - }):sys.db.Connection { - throw new haxe.exceptions.NotImplementedException("Not implemented for this platform"); - return null; - } -} diff --git a/std/sys/db/ResultSet.hx b/std/sys/db/ResultSet.hx deleted file mode 100644 index 23711241a0e..00000000000 --- a/std/sys/db/ResultSet.hx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -interface ResultSet { - /** - Get amount of rows left in this set. - Depending on a database management system accessing this field may cause - all rows to be fetched internally. However, it does not affect `next` calls. - **/ - var length(get, null):Int; - /** - Amount of columns in a row. - Depending on a database management system may return `0` if the query - did not match any rows. - **/ - var nfields(get, null):Int; - - /** - Tells whether there is a row to be fetched. - **/ - function hasNext():Bool; - /** - Fetch next row. - **/ - function next():Dynamic; - /** - Fetch all the rows not fetched yet. - **/ - function results():List; - /** - Get the value of `n`-th column of the current row. - Throws an exception if the re - **/ - function getResult(n:Int):String; - /** - Get the value of `n`-th column of the current row as an integer value. - **/ - function getIntResult(n:Int):Int; - /** - Get the value of `n`-th column of the current row as a float value. - **/ - function getFloatResult(n:Int):Float; - /** - Get the list of column names. - Depending on a database management system may return `null` if there's no - more rows to fetch. - **/ - function getFieldsNames():Null>; -} diff --git a/std/sys/db/Sqlite.hx b/std/sys/db/Sqlite.hx deleted file mode 100644 index 439182f24d7..00000000000 --- a/std/sys/db/Sqlite.hx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package sys.db; - -class Sqlite { - /** - Opens a new SQLite connection on the specified path. - - (cs) You will need a SQLite ADO.NET Provider - (see http://www.mono-project.com/docs/database-access/providers/sqlite/). - Also note that this will try to open an assembly named `Mono.Data.Sqlite` - if it wasn't loaded yet. - - (java) You will need a SQLite JDBC driver (e.g. - https://github.com/xerial/sqlite-jdbc/releases). - **/ - public static function open(file:String):Connection { - throw "Not implemented for this platform"; - return null; - } -} diff --git a/tests/RunCi.hx b/tests/RunCi.hx index 309b514be32..6e48451d3e3 100644 --- a/tests/RunCi.hx +++ b/tests/RunCi.hx @@ -21,12 +21,6 @@ class RunCi { infoMsg('Going to test: $tests'); - if (isCi()) { - changeDirectory('echoServer'); - runCommand('haxe', ['build.hxml']); - changeDirectory(cwd); - } - final downloadPath = getDownloadPath(); if (!sys.FileSystem.exists(downloadPath)) sys.FileSystem.createDirectory(downloadPath); @@ -40,13 +34,10 @@ class RunCi { //pass } - //run neko-based http echo server - var echoServer = new sys.io.Process('nekotools', ['server', '-d', 'echoServer/www/', '-p', '20200']); - infoMsg('test $test'); try { changeDirectory(unitDir); - haxelibInstallGit("haxe-utest", "utest", "master", "--always"); + haxelibInstallGit("haxe-utest", "utest", "--always"); var args = switch (ci) { case null: @@ -91,9 +82,6 @@ class RunCi { } successMsg('test ${test} succeeded'); - - echoServer.kill(); - echoServer.close(); } deploy(); diff --git a/tests/echoServer/.gitignore b/tests/echoServer/.gitignore deleted file mode 100644 index bfa848c6055..00000000000 --- a/tests/echoServer/.gitignore +++ /dev/null @@ -1 +0,0 @@ -www/echoServer.n \ No newline at end of file diff --git a/tests/echoServer/EchoServer.hx b/tests/echoServer/EchoServer.hx deleted file mode 100644 index 45004f7628c..00000000000 --- a/tests/echoServer/EchoServer.hx +++ /dev/null @@ -1,6 +0,0 @@ -class EchoServer { - static function main() { - Sys.print(neko.Web.getPostData()); - Sys.sleep(0.3); - } -} \ No newline at end of file diff --git a/tests/echoServer/build.hxml b/tests/echoServer/build.hxml deleted file mode 100644 index 58edf5255ec..00000000000 --- a/tests/echoServer/build.hxml +++ /dev/null @@ -1,2 +0,0 @@ --main EchoServer --neko www/echoServer.n \ No newline at end of file diff --git a/tests/echoServer/www/crossdomain.xml b/tests/echoServer/www/crossdomain.xml deleted file mode 100644 index b14a6a16720..00000000000 --- a/tests/echoServer/www/crossdomain.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/tests/server/src/cases/display/issues/Issue8381.hx b/tests/server/src/cases/display/issues/Issue8381.hx index 6192ff21368..ba41027ec20 100644 --- a/tests/server/src/cases/display/issues/Issue8381.hx +++ b/tests/server/src/cases/display/issues/Issue8381.hx @@ -22,6 +22,6 @@ class Issue8381 extends DisplayTestCase { offset: offset(1) }); var result = parseHover(); - Assert.equals(DisplayItemKind.ClassField, result.result.item.kind); + Assert.equals(result.result.item.kind, DisplayItemKind.ClassField); } -} \ No newline at end of file +} diff --git a/tests/server/src/cases/display/issues/Issue8602.hx b/tests/server/src/cases/display/issues/Issue8602.hx index 572254b607d..5825d2247ce 100644 --- a/tests/server/src/cases/display/issues/Issue8602.hx +++ b/tests/server/src/cases/display/issues/Issue8602.hx @@ -11,6 +11,6 @@ class Issue8602 extends DisplayTestCase { function test(_) { runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(1), wasAutoTriggered: true}); var result = parseCompletion(); - Assert.equals(Toplevel, result.result.mode.kind); + Assert.equals(result.result.mode.kind, Toplevel); } -} \ No newline at end of file +} diff --git a/tests/server/src/cases/display/issues/Issue8991.hx b/tests/server/src/cases/display/issues/Issue8991.hx index 8908c554814..4530bfa07fe 100644 --- a/tests/server/src/cases/display/issues/Issue8991.hx +++ b/tests/server/src/cases/display/issues/Issue8991.hx @@ -21,6 +21,6 @@ class Issue8991 extends DisplayTestCase { runHaxeJson([], DisplayMethods.Hover, {file: file, offset: mainHx.markers[1]}); var result = parseHover().result; - Assert.equals(DisplayItemKind.ClassField, result.item.kind); + Assert.equals(result.item.kind, DisplayItemKind.ClassField); } -} \ No newline at end of file +} diff --git a/tests/server/src/cases/display/issues/Issue9012.hx b/tests/server/src/cases/display/issues/Issue9012.hx index cf449d92ec3..dae3a41030c 100644 --- a/tests/server/src/cases/display/issues/Issue9012.hx +++ b/tests/server/src/cases/display/issues/Issue9012.hx @@ -12,6 +12,6 @@ class Issue9012 extends DisplayTestCase { runHaxeJson([], DisplayMethods.Hover, {file: file, offset: transform.markers[1]}); var result = parseHover().result; - Assert.equals(DisplayItemKind.ClassField, result.item.kind); + Assert.equals(result.item.kind, DisplayItemKind.ClassField); } -} \ No newline at end of file +} diff --git a/tests/server/src/cases/display/issues/Issue9705.hx b/tests/server/src/cases/display/issues/Issue9705.hx index c3db07c6e2b..74bbed9f9c1 100644 --- a/tests/server/src/cases/display/issues/Issue9705.hx +++ b/tests/server/src/cases/display/issues/Issue9705.hx @@ -9,7 +9,7 @@ class Issue9705 extends TestCase { runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}, res -> { Assert.equals(1, res.length); Assert.equals(1, res[0].diagnostics.length); - Assert.equals(DKUnresolvedIdentifier, res[0].diagnostics[0].kind); + Assert.equals(res[0].diagnostics[0].kind, DKUnresolvedIdentifier); var range = res[0].diagnostics[0].range; Assert.equals("Arrey".length, range.end.character - range.start.character); diff --git a/tests/server/src/utils/Vfs.hx b/tests/server/src/utils/Vfs.hx index 1f59bee5caf..3aefc5ecae7 100644 --- a/tests/server/src/utils/Vfs.hx +++ b/tests/server/src/utils/Vfs.hx @@ -41,10 +41,10 @@ class Vfs { Fs.writeFileSync(path.toString(), content); } - public function getContent(path:String) { + public function getContent(path:String):String { var path = getPhysicalPath(path); FileSystem.createDirectory(path.dir); - return Fs.readFileSync(path.toString()); + return Fs.readFileSync(path.toString()).toString(); } public function close() { diff --git a/tests/sys/src/Main.hx b/tests/sys/src/Main.hx index a9718643a19..95236e421d1 100644 --- a/tests/sys/src/Main.hx +++ b/tests/sys/src/Main.hx @@ -13,10 +13,6 @@ class Main { #if !js runner.addCase(new io.TestProcess()); #end - #if !(java || cs || lua || python || eval || js) // Sqlite is not implemented for these targets - runner.addCase(new db.TestSqliteConnection()); - runner.addCase(new db.TestSqliteResultSet()); - #end runner.addCase(new net.TestSocket()); var report = Report.create(runner); report.displayHeader = AlwaysShowHeader; diff --git a/tests/sys/src/db/SqliteSetup.hx b/tests/sys/src/db/SqliteSetup.hx deleted file mode 100644 index bbd2f768a27..00000000000 --- a/tests/sys/src/db/SqliteSetup.hx +++ /dev/null @@ -1,27 +0,0 @@ -package db; - -import sys.db.Sqlite; -import sys.db.Connection; -import sys.FileSystem; - -class SqliteSetup extends utest.Test { - var cnx:Connection; - - function setup() { - openConnection(); - cnx.request("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, num REAL, value TEXT)"); - } - - function teardown() { - cnx.request("DROP TABLE test"); - closeConnection(); - } - - function closeConnection() { - cnx.close(); - } - - function openConnection() { - cnx = Sqlite.open(':memory:'); - } -} diff --git a/tests/sys/src/db/TestSqliteConnection.hx b/tests/sys/src/db/TestSqliteConnection.hx deleted file mode 100644 index 9ed7e55b990..00000000000 --- a/tests/sys/src/db/TestSqliteConnection.hx +++ /dev/null @@ -1,60 +0,0 @@ -package db; - -import utest.Assert.*; -import sys.FileSystem; - -class TestSqliteConnection extends SqliteSetup { - function testDbName() { - equals('SQLite', cnx.dbName()); - } - - function testLastInsertId() { - cnx.request('INSERT INTO test (num, value) VALUES (10, "one")'); - equals(1, cnx.lastInsertId()); - - cnx.request('INSERT INTO test (num, value) VALUES (20, "two")'); - equals(2, cnx.lastInsertId()); - } - - function testTransactionRollback() { - cnx.startTransaction(); - cnx.request('INSERT INTO test (id, num, value) VALUES (1, 2, "one")'); - cnx.rollback(); - var result = cnx.request('SELECT * FROM test WHERE id = 1'); - isFalse(result.hasNext()); - } - - function testTransactionCommit() { - cnx.startTransaction(); - cnx.request('INSERT INTO test (id, num, value) VALUES (1, 2, "one")'); - cnx.commit(); - var result = cnx.request('SELECT * FROM test WHERE id = 1'); - same({id:1, num:2, value:'one'}, result.next()); - } - - function testIssue9700() { - var dbFile = 'temp/db.sqlite'; - try sys.FileSystem.deleteFile(dbFile) catch(_) {} - var cnx = sys.db.Sqlite.open(dbFile); - cnx.request("CREATE TABLE test (id INTEGER)"); - - function checkDataSaved(id:Int) { - cnx.request('INSERT INTO test (id) VALUES ($id)'); - cnx.close(); - cnx = sys.db.Sqlite.open(dbFile); - var result = cnx.request('SELECT * FROM test WHERE id = $id'); - same({id:id}, result.next()); - } - - cnx.startTransaction(); - cnx.commit(); - checkDataSaved(1); - - cnx.startTransaction(); - cnx.rollback(); - checkDataSaved(2); - - cnx.request('DROP TABLE test'); - cnx.close(); - } -} \ No newline at end of file diff --git a/tests/sys/src/db/TestSqliteResultSet.hx b/tests/sys/src/db/TestSqliteResultSet.hx deleted file mode 100644 index a5acb3d7608..00000000000 --- a/tests/sys/src/db/TestSqliteResultSet.hx +++ /dev/null @@ -1,62 +0,0 @@ -package db; - -import utest.Assert.*; -import haxe.ds.ReadOnlyArray; - -class TestSqliteResultSet extends SqliteSetup { - var data:ReadOnlyArray<{id:Int, num:Float, value:String}> = [ - {id:1, num:1.5, value:'one'}, - {id:10, num:10.1, value:'ten'}, - ]; - - override function setup() { - super.setup(); - var values = data.map(r -> '(${r.id}, ${r.num}, "${r.value}")').join(','); - cnx.request('INSERT INTO test (id, num, value) VALUES $values'); - } - - function testLength() { - var result = cnx.request('SELECT * FROM test'); - var length = result.length; - - result.next(); - equals(length - 1, result.length); - - for(_ in result) {} - equals(0, result.length); - } - - function testNfields() { - var result = cnx.request('SELECT * FROM test'); - equals(3, result.nfields); - } - - function testResults() { - var result = cnx.request('SELECT * FROM test'); - same(data, Lambda.array(result.results())); - } - -#if !cpp //ResultSet.getFieldsNames() is not implemented in cpp. - - function testGetFieldsNames() { - var result = cnx.request('SELECT * FROM test ORDER BY id'); - same(['id', 'num', 'value'], result.getFieldsNames()); - } -#end - - function testAsIterator() { - var result = cnx.request('SELECT * FROM test ORDER BY id'); - var rows = []; - var expected = data.copy(); - for(row in result) { - same(expected.shift(), row); - } - } - - function testGetResult() { - var result = cnx.request('SELECT * FROM test ORDER BY id'); - equals('1', result.getResult(0)); - equals(1, result.getIntResult(0)); - equals(1, result.getFloatResult(0)); - } -} \ No newline at end of file diff --git a/tests/unit/src/RunExe.hx b/tests/unit/src/RunExe.hx deleted file mode 100644 index 04ba3636103..00000000000 --- a/tests/unit/src/RunExe.hx +++ /dev/null @@ -1,39 +0,0 @@ -class RunExe { - - -static function main() { - /* - cpp: cpp/Test-debug - cs : cs/bin/cs - cs_unsafe : cs_unsafe/bin/cs_unsafe - */ - var rel_path = ""; - if (neko.Web.isModNeko) { - //mod neko: use get string - rel_path = neko.Web.getParamsString(); - //display similar to other tests - neko.Web.setHeader("Content-Type","text/plain"); - } else { - //command line arg - var args = Sys.args(); - if (args.length > 0) rel_path = args[0]; - } - - if (rel_path == "") { - neko.Lib.print("error:no path to executable specified"); - return; - } - - var p = new sys.io.Process(neko.Web.getCwd() + rel_path, []); - - try { - while ( true ) { - var c = p.stdout.readByte(); - neko.Lib.print(StringTools.htmlEscape(String.fromCharCode(c))); - } - } catch ( e : haxe.io.Eof ) { - - } - neko.Lib.print(StringTools.htmlEscape(p.stderr.readAll().toString())); - } -} diff --git a/tests/unit/src/RunJava.hx b/tests/unit/src/RunJava.hx deleted file mode 100644 index 886cf0266f7..00000000000 --- a/tests/unit/src/RunJava.hx +++ /dev/null @@ -1,17 +0,0 @@ -class RunJava { - - static function main() { - var p = new sys.io.Process("java", ["-jar", neko.Web.getCwd() + "/bin/java/Test-Debug.jar"]); - if( neko.Web.isModNeko ) - neko.Web.setHeader("Content-Type","text/plain"); - try { - while( true ) { - var c = p.stdout.readByte(); - neko.Lib.print(StringTools.htmlEscape(String.fromCharCode(c))); - } - } catch ( e : haxe.io.Eof ) { - } - neko.Lib.print(StringTools.htmlEscape(p.stderr.readAll().toString())); - } - -} diff --git a/tests/unit/src/unit/Test.hx b/tests/unit/src/unit/Test.hx index 69c95af28f2..1e4f68a537c 100644 --- a/tests/unit/src/unit/Test.hx +++ b/tests/unit/src/unit/Test.hx @@ -40,7 +40,7 @@ class Test implements utest.ITest { } function exc( f : () -> Void, ?pos:haxe.PosInfos ) { - Assert.raises(f, pos); + Assert.raises(f, /* type */ null, pos); } function unspec( f : () -> Void, ?pos ) { diff --git a/tests/unit/src/unit/TestHttp.hx b/tests/unit/src/unit/TestHttp.hx deleted file mode 100644 index 291b406c797..00000000000 --- a/tests/unit/src/unit/TestHttp.hx +++ /dev/null @@ -1,81 +0,0 @@ -package unit; - -import utest.Async; - -class TestHttp extends Test { - #if flash - public function setupClass() { - flash.system.Security.allowDomain("*"); - flash.system.Security.allowInsecureDomain("*"); - flash.system.Security.loadPolicyFile("http://localhost:20200/crossdomain.xml"); - } - #end - - static final RUN_HTTP_TESTS = - #if !github false && #end // comment out line to run http tests locally - #if (github && (java || flash || (cs && Windows))) - false - #elseif (js && !nodejs) - js.Browser.supported - #else - true - #end; - - function run(async:Async, test:()->Void) { - if (RUN_HTTP_TESTS) { - test(); - return; - } - noAssert(); - async.done(); - } - - @:timeout(1000) - public function testPostData(async:Async) run(async, () -> { - var srcStr = 'hello, world'; - var d = new haxe.Http('http://localhost:20200/echoServer.n'); - d.onData = echoStr -> { - if(echoStr != srcStr) { - assert('String data from Http request is corrupted: $echoStr'); - } - noAssert(); - async.done(); - } - d.onError = e -> { - assert('Failed Http request with string data: $e'); - async.done(); - } - d.setPostData(srcStr); - d.request(); - }); - - @:timeout(1000) - public function testPostBytes(async:Async) run(async, () -> { - var srcData = haxe.io.Bytes.alloc(256); - for(i in 0...srcData.length) { - srcData.set(i, i); - } - var d = new haxe.Http('http://localhost:20200/echoServer.n'); - d.onBytes = echoData -> { - if(srcData.length != echoData.length) { - assert('Binary data from Http request is corrupted. Wrong amount of bytes.'); - } - for(i in 0...echoData.length) { - switch [srcData.get(i), echoData.get(i)] { - case [a, b] if(a != b): - assert('Binary data from Http request is corrupted. Invalid byte value at index #$i: (src) $a != $b (echo)'); - break; - case _: - } - } - noAssert(); - async.done(); - } - d.onError = e -> { - assert('Failed Http request with binary data: $e'); - async.done(); - } - d.setPostBytes(srcData); - d.request(); - }); -} diff --git a/tests/unit/src/unit/TestMain.hx b/tests/unit/src/unit/TestMain.hx index 8b6cd45cd76..2fa17c82da7 100644 --- a/tests/unit/src/unit/TestMain.hx +++ b/tests/unit/src/unit/TestMain.hx @@ -31,13 +31,6 @@ function main() { cs.system.threading.Thread.CurrentThread.CurrentCulture = new cs.system.globalization.CultureInfo('tr-TR'); cs.Lib.applyCultureChanges(); #end - #if neko - if (neko.Web.isModNeko) - neko.Web.setHeader("Content-Type", "text/plain"); - #elseif php - if (php.Web.isModNeko) - php.Web.setHeader("Content-Type", "text/plain"); - #end #if !macro trace("Generated at: " + HelperMacros.getCompilationDate()); #end @@ -79,7 +72,6 @@ function main() { new TestNumericCasts(), new TestHashMap(), new TestRest(), - new TestHttp(), #if !no_pattern_matching new TestMatch(), #end diff --git a/tests/unit/src/unit/TestPhp.hx b/tests/unit/src/unit/TestPhp.hx index ff5aba9bb8d..06029bf4525 100644 --- a/tests/unit/src/unit/TestPhp.hx +++ b/tests/unit/src/unit/TestPhp.hx @@ -4,15 +4,17 @@ import php.*; using StringTools; -class TestPhp extends Test -{ - var list : Array; - var list2 : Array; - function empty() return true; +class TestPhp extends Test { + var list:Array; + var list2:Array; + + function empty() + return true; + function testAbstractEnum() { eq(Abstract.getName(), "Abstract"); var x = Const("foo"); - var s = switch(x) { + var s = switch (x) { case Const(s): s; case Abstract: "null"; } @@ -25,17 +27,18 @@ class TestPhp extends Test function testList2() { list2 = new Array(); - for( l in list2 ) {} // fails here + for (l in list2) {} // fails here t(true); } function testList() { list = new Array(); - for( l in list ) {} // fails here + for (l in list) {} // fails here t(true); } var switchVal = "1"; + function testIssue7257_looseSwitchComparison() { var result = switch (switchVal) { case "01": false; @@ -49,12 +52,12 @@ class TestPhp extends Test var a = Syntax.customArrayDecl([1 => 'hello', 'world' => true]); var keys:Array = []; var values:Array = []; - for(k => v in a) { + for (k => v in a) { keys.push(k); values.push(v); } - aeq(([1, 'world']:Array), keys); - aeq((['hello', true]:Array), values); + aeq(([1, 'world'] : Array), keys); + aeq((['hello', true] : Array), values); } function testIssue1828() { @@ -68,7 +71,7 @@ class TestPhp extends Test function testIssue1521() { var pattern = "$a$b"; - var result = pattern.replace("$a","A").replace("$b","B"); + var result = pattern.replace("$a", "A").replace("$b", "B"); eq("AB", result); } @@ -92,14 +95,14 @@ class TestPhp extends Test function testStupidShit9000() { var f = make(); - f.handle( function() { + f.handle(function() { eq("ok", "ok"); }); } @:analyzer(ignore) function testIssue9924() { - var v = Std.random(10); + var v:Any = Std.random(10); var GLOBALS = v; var _SERVER = v; @@ -130,7 +133,8 @@ class TestPhp extends Test Check compiler will generate proper function signature with `Ref` arguments **/ function testRef() { - function modify(i:Ref) i = 10; //avoid inlining + function modify(i:Ref) + i = 10; // avoid inlining var i = 0; modify(i); @@ -173,7 +177,9 @@ class TestPhp extends Test var result = add(null, 'b'); eq(result, 'nullb'); } - function add(a:Dynamic, b:Dynamic):Dynamic return a + b; + + function add(a:Dynamic, b:Dynamic):Dynamic + return a + b; function testStringClosureType() { var fn:Dynamic = 'foo'.toUpperCase; @@ -185,16 +191,16 @@ class TestPhp extends Test function testStringAsAnon() { var str = 'bar'; var anon:{ - function toUpperCase() : String; - function toLowerCase() : String; - function charAt( index : Int) : String; - function indexOf( str : String, ?startIndex : Int ) : Int; - function lastIndexOf( str : String, ?startIndex : Int ) : Int; - function split( delimiter : String ) : Array; - function toString() : String; - function substring( startIndex : Int, ?endIndex : Int ) : String; - function charCodeAt( index : Int) : Null ; - function substr( pos : Int, ?len : Int ) : String ; + function toUpperCase():String; + function toLowerCase():String; + function charAt(index:Int):String; + function indexOf(str:String, ?startIndex:Int):Int; + function lastIndexOf(str:String, ?startIndex:Int):Int; + function split(delimiter:String):Array; + function toString():String; + function substring(startIndex:Int, ?endIndex:Int):String; + function charCodeAt(index:Int):Null; + function substr(pos:Int, ?len:Int):String; } = str; eq(str.charAt(0), anon.charAt(0)); @@ -202,7 +208,7 @@ class TestPhp extends Test eq(str.indexOf("a"), anon.indexOf("a")); eq(str.lastIndexOf("r"), anon.lastIndexOf("r")); eq(str.split("a")[1], anon.split("a")[1]); - eq(str.substr(1),anon.substr(1, 2)); + eq(str.substr(1), anon.substr(1, 2)); eq(str.substring(0, 2), anon.substring(0, 2)); eq(str, anon.toLowerCase()); eq(str.toUpperCase(), anon.toUpperCase()); @@ -210,33 +216,33 @@ class TestPhp extends Test } function testClosureComparison() { - var fn1:()->Void; - var fn2:()->Void; + var fn1:() -> Void; + var fn2:() -> Void; eq(ClosureDummy.testStatic, ClosureDummy.testStatic); - //Waiting for a fix: https://github.com/HaxeFoundation/haxe/issues/6719 + // Waiting for a fix: https://github.com/HaxeFoundation/haxe/issues/6719 // t(ClosureDummy.testStatic == ClosureDummy.testStatic); - t((ClosureDummy:Dynamic).testStatic == (ClosureDummy:Dynamic).testStatic); - fn1 = (ClosureDummy:Dynamic).testStatic; - fn2 = (ClosureDummy:Dynamic).testStatic; + t((ClosureDummy : Dynamic).testStatic == (ClosureDummy : Dynamic).testStatic); + fn1 = (ClosureDummy : Dynamic).testStatic; + fn2 = (ClosureDummy : Dynamic).testStatic; t(fn1 == fn2); var inst = new ClosureDummy(); eq(inst.test, inst.test); - //Waiting for a fix: https://github.com/HaxeFoundation/haxe/issues/6719 + // Waiting for a fix: https://github.com/HaxeFoundation/haxe/issues/6719 // t(inst.test == inst.test); - t((inst:Dynamic).test == (inst:Dynamic).test); - fn1 = (inst:Dynamic).test; - fn2 = (inst:Dynamic).test; + t((inst : Dynamic).test == (inst : Dynamic).test); + fn1 = (inst : Dynamic).test; + fn2 = (inst : Dynamic).test; t(fn1 == fn2); var a = [fn1]; t(a.indexOf(fn2) == 0); t(a.remove(fn2)); var inst2 = new ClosureDummy(); - //Waiting for a fix: https://github.com/HaxeFoundation/haxe/issues/6719 + // Waiting for a fix: https://github.com/HaxeFoundation/haxe/issues/6719 // f(inst.test == inst2.test); a = [fn1]; - fn2 = (inst2:Dynamic).test; + fn2 = (inst2 : Dynamic).test; t(a.indexOf(fn2) < 0); f(a.remove(fn2)); } @@ -249,6 +255,7 @@ class TestPhp extends Test } var a = 2; + function testSyntaxCodeParens() { eq(8, Syntax.code("{0} * {1}", a, a + a)); } @@ -258,8 +265,6 @@ class TestPhp extends Test var phpPrefix = #if php_prefix Boot.getPrefix() + "\\" #else "" #end; eq(phpPrefix + "Array_hx", Syntax.nativeClassName(Array)); eq(phpPrefix + "unit\\Annotation", Syntax.nativeClassName(Annotation)); - var cls = php.Web; - eq(phpPrefix + "php\\Web", Syntax.nativeClassName(cls)); var enm = Annotation; eq(phpPrefix + "unit\\Annotation", Syntax.nativeClassName(enm)); } @@ -268,14 +273,14 @@ class TestPhp extends Test var expected:php.NativeString = '123456'; var actual = ''; - for(c in expected) { + for (c in expected) { actual += c; } eq(expected, actual); var actual = ''; var keys = []; - for(i => c in expected) { + for (i => c in expected) { keys.push(i); actual += c; } @@ -287,16 +292,16 @@ class TestPhp extends Test var keys:Array = ['hello', 12]; var values:Array = [10, 'world']; var a = new php.NativeArray(); - for(i in 0...keys.length) { + for (i in 0...keys.length) { a[keys[i]] = values[i]; } - var actualValues = [for(v in a) v]; + var actualValues = [for (v in a) v]; aeq(values, actualValues); var actualKeys:Array = []; var actualValues:Array = []; - for(k => v in a) { + for (k => v in a) { actualKeys.push(k); actualValues.push(v); } @@ -307,20 +312,20 @@ class TestPhp extends Test function testNativeIndexedArray() { var expected = [10, 20, 30]; var a = new NativeIndexedArray(); - for(v in expected) { + for (v in expected) { a.push(v); } - var actual = [for(v in a) v]; + var actual = [for (v in a) v]; aeq(expected, actual); var indexes = []; var values = []; - for(i => v in a) { + for (i => v in a) { indexes.push(i); values.push(v); } - aeq([for(i in 0...expected.length) i], indexes); + aeq([for (i in 0...expected.length) i], indexes); aeq(expected, values); eq('[10,20,30]', Std.string(a)); @@ -330,16 +335,16 @@ class TestPhp extends Test var keys = ['one', 'two']; var values = [1, 2]; var a = new NativeAssocArray(); - for(i in 0...keys.length) { + for (i in 0...keys.length) { a[keys[i]] = values[i]; } - var actualValues = [for(v in a) v]; + var actualValues = [for (v in a) v]; aeq(values, actualValues); var actualKeys = []; var actualValues = []; - for(k => v in a) { + for (k => v in a) { actualKeys.push(k); actualValues.push(v); } @@ -350,18 +355,24 @@ class TestPhp extends Test private class ClosureDummy { static public function testStatic() {} + public function new() {} + public function test() {} } private class DummyForRef { public var field:Int = 0; + public function new() {} - public function getThis() return this; + + public function getThis() + return this; } class Class2146 { var array:Array; + function new() { array = new Array(); } @@ -373,7 +384,7 @@ class Class2146 { a.array.push(b); b.array.push(a); c.array.push(a); - return Lambda.has(c.array,b); + return Lambda.has(c.array, b); } } @@ -382,13 +393,14 @@ enum Annotation { Const(i:String); } -private typedef Func = ()->Void; +private typedef Func = () -> Void; private abstract FunctionCaller(Func->Void) to Func->Void { - public function new(f:Func->Void) this = f; + public function new(f:Func->Void) + this = f; } -private abstract FunctionCallerWrapper( FunctionCaller ) from FunctionCaller to FunctionCaller { +private abstract FunctionCallerWrapper(FunctionCaller) from FunctionCaller to FunctionCaller { public inline function handle(callback:Func):Void - return (this:Func->Void)(callback); -} \ No newline at end of file + return (this : Func->Void)(callback); +} diff --git a/tests/unit/src/unit/issues/Issue10876.hx b/tests/unit/src/unit/issues/Issue10876.hx index a67d7a30127..919267e6e45 100644 --- a/tests/unit/src/unit/issues/Issue10876.hx +++ b/tests/unit/src/unit/issues/Issue10876.hx @@ -12,7 +12,7 @@ extern class MyDefine {} extern class MyExtern { function new(); - function create() : T; + function create():T; } @:headerCode(' @@ -30,12 +30,12 @@ public: ') #end class Issue10876 extends Test { - #if (cpp && !cppia) - function test() { - final vec = cpp.Pointer.fromStar(new MyExtern()); + #if (cpp && !cppia) + function test() { + final vec = cpp.Pointer.fromStar(new MyExtern()); final num = vec.ptr.create(); - Assert.equals(0, num); - } - #end -} \ No newline at end of file + Assert.equals(0, cast num); + } + #end +} diff --git a/tests/unit/src/unit/issues/Issue5270.hx b/tests/unit/src/unit/issues/Issue5270.hx deleted file mode 100644 index 4c38c98499e..00000000000 --- a/tests/unit/src/unit/issues/Issue5270.hx +++ /dev/null @@ -1,17 +0,0 @@ -package unit.issues; - -import php.*; - -class Issue5270 extends unit.Test { -#if php - function test() { - SuperGlobal._SERVER['CONTENT_TYPE'] = 'type'; - SuperGlobal._SERVER['HTTP_USER_AGENT'] = 'browser'; - SuperGlobal._SERVER['REDIRECT_HTTP_AUTHORIZATION'] = 'auth1'; - - eq(Web.getClientHeader('Content-Type'), 'type'); - eq(Web.getClientHeader('User-Agent'), 'browser'); - eq(Web.getClientHeader('Authorization'), 'auth1'); - } -#end -} \ No newline at end of file From d25b59f25892bdc95e959d4504f9509fc2a61f12 Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sat, 2 Dec 2023 14:58:12 +0100 Subject: [PATCH 017/184] [hl] no null check on carray access --- src/generators/genhl.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index 9b7b21e5665..705a968b8c2 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -1384,7 +1384,7 @@ and get_access ctx e = 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 + let a = eval_expr ctx a in hold ctx a; let i = eval_to ctx i HI32 in free ctx a; From 69b3faff923000ed7339c0fcc098e60c984e0935 Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sat, 2 Dec 2023 14:58:43 +0100 Subject: [PATCH 018/184] remove carray size (only pure c-like ptr) --- std/hl/CArray.hx | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/std/hl/CArray.hx b/std/hl/CArray.hx index 81c7329e82b..54673b087af 100644 --- a/std/hl/CArray.hx +++ b/std/hl/CArray.hx @@ -1,37 +1,18 @@ package hl; -#if (hl_ver >= version("1.13.0")) +#if (hl_ver >= version("1.14.0")) /** CArray is a compact array where all objects are memory aligned and stored as a single GC block. You must hold a reference to the CArray while any of the objects it contains is still referenced somewhere. **/ abstract CArray(Abstract<"hl_carray">) { - public var length(get,never) : Int; - - - #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 { + public static inline function alloc( cl : Class, size : Int ) : CArray { return cast alloc_carray( (cast cl:BaseType).__type__ , size ); } - @:hlNative("?std","carray_get") - static function getIndex( arr : CArray, index : Int ) : Dynamic { - return null; - } - - @:hlNative("?std","carray_length") - static function getLen( arr : CArray ) : Int { - return 0; - } - @:hlNative("?std","alloc_carray") static function alloc_carray( t : hl.Type, size : Int ) : CArray { return null; From cc4591743210b5e3e10276bc74d552b86ba4b8b9 Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sat, 2 Dec 2023 17:51:18 +0100 Subject: [PATCH 019/184] [hl] added hl.Api.unsafeCast, allow CArray unsafe set --- src/generators/genhl.ml | 14 +++++++++++++- src/generators/hl2c.ml | 16 ++++++++++++++-- src/generators/hlinterp.ml | 8 ++------ std/hl/Api.hx | 3 +++ std/hl/CArray.hx | 2 ++ 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index 705a968b8c2..cff859dcf9f 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -2082,6 +2082,10 @@ and eval_expr ctx e = | 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 + | "$unsafecast", [value] -> + let r = alloc_tmp ctx (to_type ctx e.etype) in + op ctx (OUnsafeCast (r, eval_expr ctx value)); + r | _ -> abort ("Unknown native call " ^ s) e.epos) | TEnumIndex v -> @@ -2469,6 +2473,14 @@ and eval_expr ctx e = free ctx ra; free ctx ridx; v + | ACArray (ra, _, ridx) -> + hold ctx ra; + hold ctx ridx; + let v = value() in + op ctx (OSetArray (ra,ridx,v)); + free ctx ridx; + free ctx ra; + v | ADynamic (ethis,f) -> let obj = eval_null_check ctx ethis in hold ctx obj; @@ -2480,7 +2492,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 _ | ACArray _ -> + | AEnum _ | ANone | AInstanceFun _ | AInstanceProto _ | AStaticFun _ | AVirtualMethod _ -> die "" __LOC__) | OpBoolOr -> let r = alloc_tmp ctx HBool in diff --git a/src/generators/hl2c.ml b/src/generators/hl2c.ml index ac567ed88ef..1e62c48e602 100644 --- a/src/generators/hl2c.ml +++ b/src/generators/hl2c.ml @@ -990,7 +990,15 @@ let generate_function ctx f = | OGetMem (r,b,idx) -> sexpr "%s = *(%s*)(%s + %s)" (reg r) (ctype (rtype r)) (reg b) (reg idx) | OGetArray (r, arr, idx) -> - sexpr "%s = ((%s*)(%s + 1))[%s]" (reg r) (ctype (rtype r)) (reg arr) (reg idx) + (match rtype arr with + | HAbstract _ -> + (match rtype r with + | HStruct _ | HObj _ -> + sexpr "%s = ((%s)%s) + %s" (reg r) (ctype (rtype r)) (reg arr) (reg idx) + | _ -> + sexpr "%s = ((%s*)%s)[%s]" (reg r) (ctype (rtype r)) (reg arr) (reg idx)) + | _ -> + sexpr "%s = ((%s*)(%s + 1))[%s]" (reg r) (ctype (rtype r)) (reg arr) (reg idx)) | OSetUI8 (b,idx,r) -> sexpr "*(unsigned char*)(%s + %s) = (unsigned char)%s" (reg b) (reg idx) (reg r) | OSetUI16 (b,idx,r) -> @@ -998,7 +1006,11 @@ let generate_function ctx f = | OSetMem (b,idx,r) -> sexpr "*(%s*)(%s + %s) = %s" (ctype (rtype r)) (reg b) (reg idx) (reg r) | OSetArray (arr,idx,v) -> - sexpr "((%s*)(%s + 1))[%s] = %s" (ctype (rtype v)) (reg arr) (reg idx) (reg v) + (match rtype arr with + | HAbstract _ -> + sexpr "((%s*)%s)[%s] = %s" (ctype (rtype v)) (reg arr) (reg idx) (reg v) + | _ -> + sexpr "((%s*)(%s + 1))[%s] = %s" (ctype (rtype v)) (reg arr) (reg idx) (reg v)) | OSafeCast (r,v) -> let tsrc = rtype v in let t = rtype r in diff --git a/src/generators/hlinterp.ml b/src/generators/hlinterp.ml index baba96be4d9..8979dcb1c01 100644 --- a/src/generators/hlinterp.ml +++ b/src/generators/hlinterp.ml @@ -2456,17 +2456,13 @@ let check code macros = reg p HI32; (match rtype v with HI32 | HI64 | HF32 | HF64 -> () | _ -> error (reg_inf r ^ " should be numeric")); | OSetArray (a,i,v) -> - reg a HArray; + (match rtype a with HAbstract ("hl_carray",_) -> () | _ -> reg a HArray); reg i HI32; ignore(rtype v); - | OUnsafeCast (a,b) -> - is_dyn a; - is_dyn b; - | OSafeCast (a,b) -> + | OUnsafeCast (a,b) | OSafeCast (a,b) -> ignore(rtype a); ignore(rtype b); | OArraySize (r,a) -> - (match rtype a with HAbstract ("hl_carray",_) -> () | _ -> reg a HArray); reg r HI32 | OType (r,_) -> reg r HType diff --git a/std/hl/Api.hx b/std/hl/Api.hx index 4c07c2e0d9b..0913fabed94 100644 --- a/std/hl/Api.hx +++ b/std/hl/Api.hx @@ -26,6 +26,9 @@ extern class Api { static inline function rethrow(v:Dynamic):Void { untyped $rethrow(v); } + static inline function unsafeCast(v:From):To { + return untyped $unsafecast(v); + } @:hlNative("std", "obj_get_field") static function getField(obj:Dynamic, hash:Int):Dynamic; @:hlNative("std", "obj_set_field") static function setField(obj:Dynamic, hash:Int, value:Dynamic):Void; @:hlNative("std", "obj_has_field") static function hasField(obj:Dynamic, hash:Int):Bool; diff --git a/std/hl/CArray.hx b/std/hl/CArray.hx index 54673b087af..e2e9e501831 100644 --- a/std/hl/CArray.hx +++ b/std/hl/CArray.hx @@ -9,6 +9,8 @@ abstract CArray(Abstract<"hl_carray">) { @:arrayAccess inline function get( index : Int ) : T return untyped this[index]; + public inline function unsafeSet( index : Int, v : T ) return untyped this[index] = v; + public static inline function alloc( cl : Class, size : Int ) : CArray { return cast alloc_carray( (cast cl:BaseType).__type__ , size ); } From 08c1f9c5576904d30589fce84729f93faa96dc88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Belin?= Date: Wed, 13 Dec 2023 08:03:22 +0100 Subject: [PATCH 020/184] [js] Add externs for the Screen Wake Lock API (#11421) --- std/js/html/Navigator.hx | 5 +++ std/js/html/WakeLock.hx | 74 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 std/js/html/WakeLock.hx diff --git a/std/js/html/Navigator.hx b/std/js/html/Navigator.hx index a192bad3016..d044b43fe7d 100644 --- a/std/js/html/Navigator.hx +++ b/std/js/html/Navigator.hx @@ -106,6 +106,11 @@ extern class Navigator { var onLine(default,null) : Bool; var storage(default,null) : StorageManager; + /** + Returns a `WakeLock` object which allows a document to acquire a screen wake lock. + **/ + var wakeLock(default,null) : WakeLock; + @:overload( function( duration : Int ) : Bool {} ) function vibrate( pattern : Array ) : Bool; function javaEnabled() : Bool; diff --git a/std/js/html/WakeLock.hx b/std/js/html/WakeLock.hx new file mode 100644 index 00000000000..4d8c7a4e97e --- /dev/null +++ b/std/js/html/WakeLock.hx @@ -0,0 +1,74 @@ +/* + * Copyright (C)2005-2023 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.html; + +import js.lib.Promise; + +/** + Prevents device screens from dimming or locking when an application needs to keep running. + + Documentation [WakeLock](https://developer.mozilla.org/en-US/docs/Web/API/WakeLock) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/WakeLock/contributors.txt), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/). + + @see +**/ +@:native("WakeLock") +extern class WakeLock { + + /** + Returns a `Promise` that resolves with a `WakeLockSentinel` object, which allows control over screen dimming and locking. + **/ + function request(?type: WakeLockType): Promise; +} + +/** + Provides a handle to the underlying platform wake lock and can be manually released and reacquired. + + Documentation [WakeLockSentinel](https://developer.mozilla.org/en-US/docs/Web/API/WakeLockSentinel) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/WakeLockSentinel/contributors.txt), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/). + + @see +**/ +@:native("WakeLockSentinel") +extern class WakeLockSentinel extends EventTarget { + + /** + A boolean a that indicates whether a `WakeLockSentinel` has been released yet. + **/ + final released: Bool; + + /** + A string representation of the currently acquired `WakeLockSentinel` type. + **/ + final type: WakeLockType; + + /** + Releases the `WakeLockSentinel`, returning a `Promise` that is resolved once the sentinel has been successfully released. + **/ + function release(): Promise; +} + +/** + Indicates the type of `WakeLockSentinel` to be acquired. +**/ +enum abstract WakeLockType(String) from String to String { + var Screen = "screen"; +} From e391fda1a29a33155e1dd3ba96aa5e824afc03a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Belin?= Date: Wed, 13 Dec 2023 08:03:33 +0100 Subject: [PATCH 021/184] [js] Add externs for the Web Share API (#11423) --- std/js/html/Navigator.hx | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/std/js/html/Navigator.hx b/std/js/html/Navigator.hx index d044b43fe7d..aaf95214b3b 100644 --- a/std/js/html/Navigator.hx +++ b/std/js/html/Navigator.hx @@ -127,4 +127,41 @@ extern class Navigator { function sendBeacon( url : String, ?data : Blob ) : Bool; function requestMediaKeySystemAccess( keySystem : String, supportedConfigurations : Array ) : Promise; function taintEnabled() : Bool; -} \ No newline at end of file + + /** + Returns `true` if the equivalent call to `share()` would succeed. + Returns `false` if the data cannot be validated. + **/ + function canShare(?data: NavigatorShareData): Bool; + + /** + Invokes the native sharing mechanism of the device to share data such as text, URLs, or files. + **/ + function share(data: NavigatorShareData): Promise; +} + +/** + An object containing data to share. +**/ +typedef NavigatorShareData = { + + /** + An array of `File` objects representing files to be shared. + **/ + var ?files: Array; + + /** + A string representing text to be shared. + **/ + var ?text: String; + + /** + A string representing the title to be shared. + **/ + var ?title: String; + + /** + A string representing a URL to be shared + **/ + var ?url: String; +} From ca87189fca9d815e20627386de0d9e450f56ebc5 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 13 Dec 2023 08:04:09 +0100 Subject: [PATCH 022/184] [js] Update Object and Symbol externs (#11331) * [js] Update js.lib.Object and js.lib.Symbol From their implementation in js-object haxelib * Restore ?field syntax * Reduce diff --- std/js/Object.hx | 2 +- std/js/lib/Object.hx | 204 +++++++++++++++++++++++++++++++----------- std/js/lib/Proxy.hx | 4 +- std/js/lib/Reflect.hx | 10 +-- std/js/lib/Symbol.hx | 75 +++++++++++++++- 5 files changed, 230 insertions(+), 65 deletions(-) diff --git a/std/js/Object.hx b/std/js/Object.hx index 7da188a7248..6b2ecfa3e42 100644 --- a/std/js/Object.hx +++ b/std/js/Object.hx @@ -24,4 +24,4 @@ package js; @:deprecated typedef Object = js.lib.Object; @:deprecated typedef ObjectPrototype = js.lib.Object.ObjectPrototype; -@:deprecated typedef ObjectPropertyDescriptor = js.lib.Object.ObjectPropertyDescriptor; +@:deprecated typedef ObjectPropertyDescriptor = js.lib.Object.ObjectPropertyDescriptor; diff --git a/std/js/lib/Object.hx b/std/js/lib/Object.hx index 55358b7d382..7b647b9c998 100644 --- a/std/js/lib/Object.hx +++ b/std/js/lib/Object.hx @@ -33,35 +33,64 @@ import haxe.DynamicAccess; @:native("Object") extern class Object { /** - Copies the values of all enumerable own properties from one or more - source objects to a target object. + The Object.assign() method is used to copy the values of all enumerable + own properties from one or more source objects to a target object. It + will return the target object. + + Note: this is an ES2015 feature + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign **/ - static function assign(target:T, sources:Rest<{}>):T; + static function assign(target:TSource, sources:Rest<{}>):TDest; /** - Creates a new object with the specified prototype object and properties. + The Object.create() method create a new object, using an existing object + to provide the newly created object's __proto__ . (see browser console + for visual evidence.) + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create **/ - @:pure static function create(proto:{}, ?propertiesObject:DynamicAccess):T; + @:pure static function create(proto:Null<{}>, ?propertiesObject:DynamicAccess>):T; /** - Adds the named properties described by the given descriptors to an object. + The Object.defineProperties() method defines new or modifies existing + properties directly on an object, returning the object. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties **/ - static function defineProperties(obj:T, props:DynamicAccess):T; + static function defineProperties(obj:T, props:DynamicAccess>):T; /** - Adds the named property described by a given descriptor to an object. + The static method Object.defineProperty() defines a new property directly + on an object, or modifies an existing property on an object, and returns + the object. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty **/ - @:overload(function(obj:T, prop:Symbol, descriptor:ObjectPropertyDescriptor):T {}) - static function defineProperty(obj:T, prop:String, descriptor:ObjectPropertyDescriptor):T; + @:overload(function(obj:T, prop:Symbol, descriptor:ObjectPropertyDescriptor):T {}) + static function defineProperty(obj:T, prop:String, descriptor:ObjectPropertyDescriptor):T; /** - Returns an array containing all of the [key, value] pairs of a given - object's own enumerable string properties. + The Object.entries() method returns an array of a given object's own + enumerable property [key, value] pairs, in the same order as that + provided by a for...in loop (the difference being that a for-in loop + enumerates properties in the prototype chain as well). + + Note: this is an ES2017 feature + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries **/ - @:pure static function entries(obj:{}):Array; + @:pure static function entries(obj:T):Array; /** - Freezes an object: other code can't delete or change any properties. + The Object.freeze() method freezes an object: that is, prevents new + properties from being added to it; prevents existing properties from + being removed; and prevents existing properties, or their enumerability, + configurability, or writability, from being changed, it also prevents the + prototype from being changed. + The method returns the passed object. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze **/ static function freeze(obj:T):T; @@ -72,76 +101,149 @@ extern class Object { @:pure static function fromEntries(iterable:Any):T; /** - Returns a property descriptor for a named property on an object. + The Object.getOwnPropertyDescriptor() method returns a property + descriptor for an own property (that is, one directly present on an + object and not in the object's prototype chain) of a given object. + + In ES5, if the first argument to this method is not an object (a + primitive), then it will cause a TypeError. In ES2015, a non-object + first argument will be coerced to an object at first. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor **/ - @:overload(function(target:Array, propertyKey:Int):Null {}) - @:overload(function(obj:{}, prop:Symbol):Null {}) - @:pure static function getOwnPropertyDescriptor(obj:{}, prop:String):Null; + @:overload(function(obj:String, prop:Symbol):Null> {}) + @:overload(function(obj:String, prop:String):Null> {}) + @:overload(function(target:Array, propertyKey:Int):Null> {}) + @:overload(function(obj:T, prop:Symbol):Null> {}) + @:pure static function getOwnPropertyDescriptor(obj:T, prop:String):Null>; /** - Returns an array containing the names of all of the given object's own - enumerable and non-enumerable properties. + The Object.getOwnPropertyDescriptors() method returns all own property + descriptors of a given object. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors **/ - @:pure static function getOwnPropertyNames(obj:{}):Array; + @:overload(function(target:String):DynamicAccess> {}) + @:overload(function(target:Array):DynamicAccess> {}) + @:pure static function getOwnPropertyDescriptors(obj:T):DynamicAccess>; /** - Returns an array of all symbol properties found directly upon a given object. + The Object.getOwnPropertyNames() method returns an array of all + properties (including non-enumerable properties except for those which + use Symbol) found directly upon a given object. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames **/ - @:pure static function getOwnPropertySymbols(obj:{}):Array; + @:pure static function getOwnPropertyNames(obj:T):Array; /** - Returns the prototype of the specified object. + The Object.getOwnPropertySymbols() method returns an array of all symbol + properties found directly upon a given object. + + Note: this is an ES2015 feature + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertySymbols **/ - @:pure static function getPrototypeOf(obj:{}):Null; + @:pure static function getOwnPropertySymbols(obj:T):Array; /** - Compares if two values are the same value. Equates all NaN values - (which differs from both Abstract Equality Comparison and - Strict Equality Comparison). + The Object.getPrototypeOf() method returns the prototype (i.e. the value + of the internal [[Prototype]] property) of the specified object. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf **/ - @:pure static function is(value1:T, value2:T):Bool; + @:pure static function getPrototypeOf(obj:T):TProto; /** - Determines if extending of an object is allowed. + The Object.is() method determines whether two values are the same value. + + Note: this is an ES2015 feature + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is **/ - @:pure static function isExtensible(obj:{}):Bool; + @:native("is") @:pure static function isSame(obj1:T, obj2:T):Bool; /** - Determines if an object was frozen. + The Object.is() method determines whether two values are the same value. + + Note: this is an ES2015 feature + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is **/ - @:pure static function isFrozen(obj:{}):Bool; + @:deprecated("Use Object.isSame()") + @:pure static function is(obj1:T, obj2:T):Bool; /** - Determines if an object is sealed. + The Object.isExtensible() method determines if an object is extensible + (whether it can have new properties added to it). + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible **/ - @:pure static function isSealed(obj:{}):Bool; + @:pure static function isExtensible(obj:T):Bool; /** - Returns an array containing the names of all of the given object's own - enumerable string properties. + The Object.isFrozen() determines if an object is frozen. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen + **/ + @:pure static function isFrozen(obj:T):Bool; + + /** + The Object.isSealed() method determines if an object is sealed. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed **/ - @:pure static function keys(obj:{}):Array; + @:pure static function isSealed(obj:T):Bool; /** - Prevents any extensions of an object. + The Object.keys() method returns an array of a given object's own + enumerable properties, in the same order as that provided by a for...in + loop (the difference being that a for-in loop enumerates properties in + the prototype chain as well). + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys + **/ + @:pure static function keys(obj:T):Array; + + /** + The Object.preventExtensions() method prevents new properties from ever + being added to an object (i.e. prevents future extensions to the object). + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions **/ static function preventExtensions(obj:T):T; /** - Prevents other code from deleting properties of an object. + The Object.seal() method seals an object, preventing new properties from + being added to it and marking all existing properties as + non-configurable. Values of present properties can still be changed as + long as they are writable. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal **/ static function seal(obj:T):T; /** - Sets the prototype (i.e., the internal Prototype property). + The Object.setPrototypeOf() method sets the prototype (i.e., the internal + [[Prototype]] property) of a specified object to another object or null. + + Note: this is an ES2015 feature + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf **/ - static function setPrototypeOf(obj:T, prototype:Null<{}>):T; + static function setPrototypeOf(obj:T, proto:Null):T; /** - Returns an array containing the values that correspond to all of - a given object's own enumerable string properties. + The Object.values() method returns an array of a given object's own + enumerable property values, in the same order as that provided by a + for...in loop (the difference being that a for-in loop enumerates + properties in the prototype chain as well). + + Note: this is an ES2017 feature + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values **/ - @:pure static function values(obj:{}):Array; + @:pure static function values(obj:T):Array; /** Allows the addition of properties to all objects of type Object. @@ -196,11 +298,10 @@ typedef ObjectPrototype = { /** @see **/ -typedef ObjectPropertyDescriptor = { +typedef ObjectPropertyDescriptor = { /** `true` if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object. - Defaults to `false`. **/ var ?configurable:Bool; @@ -208,7 +309,6 @@ typedef ObjectPropertyDescriptor = { /** `true` if and only if this property shows up during enumeration of the properties on the corresponding object. - Defaults to `false`. **/ var ?enumerable:Bool; @@ -217,12 +317,11 @@ typedef ObjectPropertyDescriptor = { The value associated with the property. Can be any valid JavaScript value (number, object, function, etc). **/ - var ?value:Any; + var ?value:TProp; /** `true` if and only if the value associated with the property may be changed with an assignment operator. - Defaults to `false`. **/ var ?writable:Bool; @@ -235,7 +334,7 @@ typedef ObjectPropertyDescriptor = { property is defined due to inheritance). The return value will be used as the value of the property. **/ - var ?get:Void->Any; + var ?get:Void->TProp; /** A function which serves as a setter for the property, or undefined if @@ -243,7 +342,7 @@ typedef ObjectPropertyDescriptor = { is called with one argument (the value being assigned to the property) and with `this` set to the object through which the property is assigned. **/ - var ?set:Any->Void; + var ?set:TProp->Void; } /** @@ -252,7 +351,6 @@ typedef ObjectPropertyDescriptor = { abstract ObjectEntry(Array) { public var key(get, never):String; public var value(get, never):Any; - inline function get_key():String return this[0]; diff --git a/std/js/lib/Proxy.hx b/std/js/lib/Proxy.hx index 24c7668f5c1..e3848e9b479 100644 --- a/std/js/lib/Proxy.hx +++ b/std/js/lib/Proxy.hx @@ -65,12 +65,12 @@ typedef ProxyHandler = { /** A trap for `Object.getOwnPropertyDescriptor`. **/ - var ?getOwnPropertyDescriptor:(target:T, prop:EitherType) -> Null; + var ?getOwnPropertyDescriptor:(target:T, prop:EitherType) -> Null>; /** A trap for `Object.defineProperty`. **/ - var ?defineProperty:(target:T, property:EitherType, descriptor:ObjectPropertyDescriptor) -> Bool; + var ?defineProperty:(target:T, property:EitherType, descriptor:ObjectPropertyDescriptor) -> Bool; /** A trap for the `in` operator. diff --git a/std/js/lib/Reflect.hx b/std/js/lib/Reflect.hx index cce68769ef7..eca2fbf5703 100644 --- a/std/js/lib/Reflect.hx +++ b/std/js/lib/Reflect.hx @@ -49,8 +49,8 @@ extern class Reflect { /** Similar to `Object.defineProperty()`. Returns a Bool. */ - @:overload(function(target:{}, propertyKey:Symbol, attributes:ObjectPropertyDescriptor):Bool {}) - static function defineProperty(target:{}, propertyKey:String, attributes:ObjectPropertyDescriptor):Bool; + @:overload(function(target:{}, propertyKey:Symbol, attributes:ObjectPropertyDescriptor):Bool {}) + static function defineProperty(target:{}, propertyKey:String, attributes:ObjectPropertyDescriptor):Bool; /** The `delete` operator as a function. Equivalent to calling `delete target[name]`. @@ -71,9 +71,9 @@ extern class Reflect { Returns a property descriptor of the given property if it exists on the object, `undefined` otherwise. */ - @:overload(function(target:Array, propertyKey:Int):Null {}) - @:overload(function(target:{}, propertyKey:Symbol):Null {}) - @:pure static function getOwnPropertyDescriptor(target:{}, propertyKey:String):Null; + @:overload(function(target:Array, propertyKey:Int):Null> {}) + @:overload(function(target:{}, propertyKey:Symbol):Null> {}) + @:pure static function getOwnPropertyDescriptor(target:{}, propertyKey:String):Null>; /** Same as `Object.getPrototypeOf()`. diff --git a/std/js/lib/Symbol.hx b/std/js/lib/Symbol.hx index 61960149ce1..39393e9b7b7 100644 --- a/std/js/lib/Symbol.hx +++ b/std/js/lib/Symbol.hx @@ -26,20 +26,28 @@ package js.lib; extern class Symbol { /** To create a new primitive symbol, use `new Symbol()` with an optional string as its `description`. - NOTE: Unlike in plain JavaScript, `new Symbol()` syntax is used in Haxe. This generates a `Symbol(...)` expression as required by the JavaScript specification. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol **/ @:pure @:selfCall function new(?description:String); /** - Searches for existing symbols with the given key and returns it if found. - Otherwise a new symbol gets created in the global symbol registry with this key. + The Symbol.for(key) method searches for existing symbols in a + runtime-wide symbol registry with the given key and returns it if found. + Otherwise a new symbol gets created in the global symbol registry with + this key. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for **/ @:native("for") static function for_(key:String):Symbol; /** - Retrieves a shared symbol key from the global symbol registry for the given symbol. + The Symbol.keyFor(sym) method retrieves a shared symbol key from the + global symbol registry for the given symbol. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/keyFor **/ @:pure static function keyFor(sym:Symbol):Null; @@ -58,6 +66,65 @@ extern class Symbol { **/ static var asyncIterator(default, null):Symbol; + /** + A method that matches against a string, also used to determine if an + object may be used as a regular expression. Used by + String.prototype.match(). + **/ + static var match(default, null):Symbol; + + /** + A method that replaces matched substrings of a string. Used by + String.prototype.replace(). + **/ + static var replace(default, null):Symbol; + + /** + A method that returns the index within a string that matches the regular + expression. Used by String.prototype.search(). + **/ + static var search(default, null):Symbol; + + /** + A method that splits a string at the indices that match a regular + expression. Used by String.prototype.split(). + **/ + static var split(default, null):Symbol; + + /** + A method determining if a constructor object recognizes an object as its + instance. Used by instanceof. + **/ + static var hasInstance(default, null):Symbol; + + /** + A Boolean value indicating if an object should be flattened to its array + elements. Used by Array.prototype.concat(). + **/ + static var isConcatSpreadable(default, null):Symbol; + + /** + An object value of whose own and inherited property names are excluded + from the with environment bindings of the associated object. + **/ + static var unscopables(default, null):Symbol; + + /** + A constructor function that is used to create derived objects. + **/ + static var species(default, null):Symbol; + + /** + A method converting an object to a primitive value. + **/ + static var toPrimitive(default, null):Symbol; + + /** + A string value used for the default description of an object. Used by + Object.prototype.toString(). + **/ + static var toStringTag(default, null):Symbol; + /** Retrieve symbol from a given `object`. From 787c3a406d2e088bcf47d36049dbb73d43a5f429 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 13 Dec 2023 08:20:19 +0100 Subject: [PATCH 023/184] [dce] clean up operator handling closes #11427 --- src/optimization/dce.ml | 26 ++++++++++++++----- tests/misc/python/projects/Issue11427/Main.hx | 7 +++++ .../python/projects/Issue11427/build.hxml | 3 +++ .../projects/Issue11427/build.hxml.stdout | 1 + 4 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 tests/misc/python/projects/Issue11427/Main.hx create mode 100644 tests/misc/python/projects/Issue11427/build.hxml create mode 100644 tests/misc/python/projects/Issue11427/build.hxml.stdout diff --git a/src/optimization/dce.ml b/src/optimization/dce.ml index e6080b3d880..498887fb14d 100644 --- a/src/optimization/dce.ml +++ b/src/optimization/dce.ml @@ -511,6 +511,15 @@ and expr_field dce e fa is_call_expr = end; expr dce e; +and check_op dce op = match op with + | OpMod -> + check_and_add_feature dce "binop_%"; + | OpUShr -> + check_and_add_feature dce "binop_>>>"; + | OpAssignOp op -> + check_op dce op + | _ -> + () and expr dce e = mark_t dce e.epos e.etype; @@ -605,10 +614,15 @@ and expr dce e = check_and_add_feature dce "dynamic_array_read"; expr dce e1; expr dce e2; - | TBinop( (OpAssign | OpAssignOp _), ({eexpr = TArray({etype = TDynamic None},_)} as e1), e2) -> + | TBinop(OpAssign, ({eexpr = TArray({etype = TDynamic None},_)} as e1), e2) -> check_and_add_feature dce "dynamic_array_write"; expr dce e1; expr dce e2; + | TBinop(OpAssignOp op, ({eexpr = TArray({etype = TDynamic None},_)} as e1), e2) -> + check_op dce op; + check_and_add_feature dce "dynamic_array_write"; + expr dce e1; + expr dce e2; | TArray(({etype = t} as e1),e2) when is_array t -> check_and_add_feature dce "array_read"; expr dce e1; @@ -629,10 +643,12 @@ and expr dce e = expr dce e1; expr dce e2; | TBinop(OpAssignOp op,({eexpr = TField(_,(FDynamic _ as fa) )} as e1),e2) -> + check_op dce op; check_dynamic_write dce fa; expr dce e1; expr dce e2; | TBinop(OpAssignOp op,({eexpr = TField(_,(FAnon cf as fa) )} as e1),e2) -> + check_op dce op; if Meta.has Meta.Optional cf.cf_meta then check_anon_optional_write dce fa else @@ -655,12 +671,8 @@ and expr dce e = check_and_add_feature dce "type_param_binop_!="; expr dce e1; expr dce e2; - | TBinop(OpMod,e1,e2) -> - check_and_add_feature dce "binop_%"; - expr dce e1; - expr dce e2; - | TBinop((OpUShr | OpAssignOp OpUShr),e1,e2) -> - check_and_add_feature dce "binop_>>>"; + | TBinop(op,e1,e2) -> + check_op dce op; expr dce e1; expr dce e2; | TCall(({ eexpr = TField(ef, fa) } as e2), el ) -> diff --git a/tests/misc/python/projects/Issue11427/Main.hx b/tests/misc/python/projects/Issue11427/Main.hx new file mode 100644 index 00000000000..93519f1330d --- /dev/null +++ b/tests/misc/python/projects/Issue11427/Main.hx @@ -0,0 +1,7 @@ +class Main { + public static function main() { + var a:Int = -5; + a = a % 7; + trace(a); + } +} \ No newline at end of file diff --git a/tests/misc/python/projects/Issue11427/build.hxml b/tests/misc/python/projects/Issue11427/build.hxml new file mode 100644 index 00000000000..fcf1ca0c626 --- /dev/null +++ b/tests/misc/python/projects/Issue11427/build.hxml @@ -0,0 +1,3 @@ +-python bin/main.py +--main Main +-cmd python3 bin/main.py diff --git a/tests/misc/python/projects/Issue11427/build.hxml.stdout b/tests/misc/python/projects/Issue11427/build.hxml.stdout new file mode 100644 index 00000000000..c67f81a3f48 --- /dev/null +++ b/tests/misc/python/projects/Issue11427/build.hxml.stdout @@ -0,0 +1 @@ +-5 \ No newline at end of file From 39642c94d895b73678f719f4a2fe9b5ca89bbdc8 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 13 Dec 2023 08:49:05 +0100 Subject: [PATCH 024/184] [typer] align null coalescing top down inference with normal if/else closes #11425 --- src/typing/typer.ml | 31 ++++++------ tests/unit/src/unit/issues/Issue11425.hx | 64 ++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 17 deletions(-) create mode 100644 tests/unit/src/unit/issues/Issue11425.hx diff --git a/src/typing/typer.ml b/src/typing/typer.ml index d7d1405a492..3b2a53ffad8 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -1562,8 +1562,7 @@ and type_cast ctx e t p = let texpr = loop t in mk (TCast (type_expr ctx e WithType.value,Some texpr)) t p -and make_if_then_else ctx e0 e1 e2 with_type p = - let e1,e2,t = match with_type with +and get_if_then_else_operands ctx e1 e2 with_type = match with_type with | WithType.NoValue -> e1,e2,ctx.t.tvoid | WithType.Value _ -> e1,e2,unify_min ctx [e1; e2] | WithType.WithType(t,src) when (match follow t with TMono _ -> true | t -> ExtType.is_void t) -> @@ -1572,7 +1571,9 @@ and make_if_then_else ctx e0 e1 e2 with_type p = let e1 = AbstractCast.cast_or_unify ctx t e1 e1.epos in let e2 = AbstractCast.cast_or_unify ctx t e2 e2.epos in e1,e2,t - in + +and make_if_then_else ctx e0 e1 e2 with_type p = + let e1,e2,t = get_if_then_else_operands ctx e1 e2 with_type in mk (TIf (e0,e1,Some e2)) t p and type_if ctx e e1 e2 with_type is_ternary p = @@ -1847,26 +1848,22 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) = let vr = new value_reference ctx in let e1 = type_expr ctx (Expr.ensure_block e1) with_type in let e2 = type_expr ctx (Expr.ensure_block e2) (WithType.with_type e1.etype) in - let tmin = unify_min ctx [e1; e2] in - let e1 = vr#as_var "tmp" {e1 with etype = ctx.t.tnull tmin} in - let e_null = Builder.make_null e1.etype e1.epos in - let e_cond = mk (TBinop(OpNotEq,e1,e_null)) ctx.t.tbool e1.epos in - + let e1,e2,tmin = get_if_then_else_operands ctx e1 e2 with_type in let rec follow_null t = match t with | TAbstract({a_path = [],"Null"},[t]) -> follow_null t | _ -> t in let iftype = if DeadEnd.has_dead_end e2 then - WithType.with_type (follow_null e1.etype) - else - let t = match e2.etype with - | TAbstract({a_path = [],"Null"},[t]) -> tmin - | _ -> follow_null tmin - in - WithType.with_type t - in - let e_if = make_if_then_else ctx e_cond e1 e2 iftype p in + follow_null e1.etype + else match e2.etype with + | TAbstract({a_path = [],"Null"},[t]) -> tmin + | _ -> follow_null tmin + in + let e1 = vr#as_var "tmp" {e1 with etype = ctx.t.tnull tmin} in + let e_null = Builder.make_null e1.etype e1.epos in + let e_cond = mk (TBinop(OpNotEq,e1,e_null)) ctx.t.tbool e1.epos in + let e_if = mk (TIf(e_cond,e1,Some e2)) iftype p in vr#to_texpr e_if | EBinop (OpAssignOp OpNullCoal,e1,e2) -> let e_cond = EBinop(OpNotEq,e1,(EConst(Ident "null"), p)) in diff --git a/tests/unit/src/unit/issues/Issue11425.hx b/tests/unit/src/unit/issues/Issue11425.hx new file mode 100644 index 00000000000..07bfd56df4b --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11425.hx @@ -0,0 +1,64 @@ +package unit.issues; + +private enum VariantType { + VT_String(s:String); + VT_Float(s:Float); +} + +@:transitive +private abstract Variant(VariantType) from VariantType { + @:from static function fromString(s:String):Variant { + return VT_String(s); + } + + @:to public function toString():String { + if (this == null) { + return null; + } + return switch (this) { + case VT_String(s): s; + case VT_Float(s): Std.string(s); + } + } + + @:from static function fromFloat(s:Float):Variant { + return VT_Float(s); + } + + @:to public function toFloat():Null { + if (this == null) { + return null; + } + return switch (this) { + case VT_Float(s): s; + default: throw "Variant Type Error (" + this + ")"; + } + } +} + +class Issue11425 extends Test { + function test() { + var variant1:Variant = 4.0; + + var testValue1:Float = variant1; // Works fine. + // discrepency between "... != ... ? ... : ..." and "... ?? ... " + var testValue2:Float = (variant1 != null) ? variant1 : 1.0; // Works fine. + var testValue3:Float = variant1 ?? 1.0; // ERROR: Float should be Variant + + // type hint testValue6 as Variant + var testValue6:Variant = (variant1 != null) ? variant1 : 1.0; // Works fine. + // type hint testValue7 as Variant + var testValue7:Variant = variant1 ?? 1.0; // ERROR: Float should be Variant + + // using "cast" to get around compilation and see generated output: + // though presumably cast is influencing the output also + var testValue8:Float = (variant1 != null) ? variant1 : 1.0; // Works fine. + // generated: variant1 != null ? Variant.toFloat(variant1) : 1.0 + var testValue9:Float = variant1 ?? cast 1.0; // Works fine. + // generated: Variant.toFloat(variant1 != null ? variant1 : 1.0) + var testValue10 = variant1 ?? cast 1.0; // Works fine. + // generated: variant1 != null ? variant1 : 1.0 + + utest.Assert.pass(); + } +} From 9932f26a1f70201822bae76d2585437f1a5e26bd Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 13 Dec 2023 09:35:19 +0100 Subject: [PATCH 025/184] [display] browse for EDisplay when calls fail closes #11422 --- src/core/ast.ml | 13 ++++++++++ src/typing/callUnification.ml | 35 +++++++++++++++++++-------- tests/display/src/cases/Issue11422.hx | 32 ++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 tests/display/src/cases/Issue11422.hx diff --git a/src/core/ast.ml b/src/core/ast.ml index d578a6f8ff8..e25cd3a4816 100644 --- a/src/core/ast.ml +++ b/src/core/ast.ml @@ -863,6 +863,19 @@ let iter_expr loop (e,p) = opt f.f_expr | EVars vl -> List.iter (fun v -> opt v.ev_expr) vl +let exists check e = + let rec loop (e,p) = + if check e then + raise Exit + else + iter_expr loop (e,p) + in + try + loop e; + false + with Exit -> + true + let s_object_key_name name = function | DoubleQuotes -> "\"" ^ StringHelper.s_escape name ^ "\"" | NoQuotes -> name diff --git a/src/typing/callUnification.ml b/src/typing/callUnification.ml index bfeb4376d5e..a5d82477854 100644 --- a/src/typing/callUnification.ml +++ b/src/typing/callUnification.ml @@ -350,14 +350,6 @@ let unify_field_call ctx fa el_typed el p inline = in loop candidates in - let fail_fun () = - let tf = TFun(List.map (fun _ -> ("",false,t_dynamic)) el,t_dynamic) in - let call () = - let ef = mk (TField(fa.fa_on,FieldAccess.apply_fa fa.fa_field fa.fa_host)) tf fa.fa_pos in - mk (TCall(ef,[])) t_dynamic p - in - make_field_call_candidate [] t_dynamic [] tf fa.fa_field call - in let maybe_check_access cf = (* type_field doesn't check access for overloads, so let's check it here *) begin match co with @@ -367,13 +359,34 @@ let unify_field_call ctx fa el_typed el p inline = () end; in + (* There's always a chance that we never even came across the EDisplay in an argument, so let's look for it (issue #11422). *) + let check_display_args () = + if ctx.is_display_file then begin + let rec loop el = match el with + | [] -> + () + | e :: el -> + if Ast.exists (function EDisplay _ -> true | _ -> false) e then + ignore(type_expr ctx e WithType.value) + else + loop el + in + loop el + end; + in match candidates with | [cf] -> if overload_kind = OverloadProper then maybe_check_access cf; begin try commit_delayed_display (attempt_call cf false) with Error _ when Common.ignore_error ctx.com -> - fail_fun(); + check_display_args(); + let tf = TFun(List.map (fun _ -> ("",false,t_dynamic)) el,t_dynamic) in + let call () = + let ef = mk (TField(fa.fa_on,FieldAccess.apply_fa fa.fa_field fa.fa_host)) tf fa.fa_pos in + mk (TCall(ef,[])) t_dynamic p + in + make_field_call_candidate [] t_dynamic [] tf fa.fa_field call end | _ -> let candidates,failures = attempt_calls candidates in @@ -385,6 +398,7 @@ let unify_field_call ctx fa el_typed el p inline = ) delayed_display; cf,err ) failures in + check_display_args(); let failures = remove_duplicates (fun (_,e1) (_,e2) -> (MessageReporting.print_error e1) <> (MessageReporting.print_error e2)) failures in begin match failures with | [_,err] -> @@ -408,7 +422,8 @@ let unify_field_call ctx fa el_typed el p inline = end in if overload_kind = OverloadProper then begin match Overloads.Resolution.reduce_compatible candidates with - | [] -> fail() + | [] -> + fail() | [fcc] -> maybe_check_access fcc.fc_field; commit_delayed_display fcc diff --git a/tests/display/src/cases/Issue11422.hx b/tests/display/src/cases/Issue11422.hx new file mode 100644 index 00000000000..e50d4e8784f --- /dev/null +++ b/tests/display/src/cases/Issue11422.hx @@ -0,0 +1,32 @@ +package cases; + +class Issue11422 extends DisplayTestCase { + /** + class Main { + static function main() { + var string = ""; + foo(0.0, s{-1-}); + } + + static function foo(a:Int, name:String):Void {} + } + **/ + function test() { + eq(true, hasToplevel(toplevel(pos(1)), "local", "string")); + } + + /** + class Main { + static function main() { + var string = ""; + foo(0.0, s{-1-}); + } + + overload static function foo(a:Int, name:String):Void {} + overload static function foo(a:Bool, name:String):Void {} + } + **/ + function testOverload() { + eq(true, hasToplevel(toplevel(pos(1)), "local", "string")); + } +} From 989bec7b06403a3c8a267cdc88da154c21e1d3f7 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 13 Dec 2023 09:55:05 +0100 Subject: [PATCH 026/184] [tests] dodge for green CI see #11425 --- tests/unit/src/unit/TestNullCoalescing.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/src/unit/TestNullCoalescing.hx b/tests/unit/src/unit/TestNullCoalescing.hx index 76eb4895fbc..e6965b7ebcd 100644 --- a/tests/unit/src/unit/TestNullCoalescing.hx +++ b/tests/unit/src/unit/TestNullCoalescing.hx @@ -119,6 +119,7 @@ class TestNullCoalescing extends Test { eq(arr[i], v); final arr = []; + #if !cs function item(n) { arr.push(n); return null; @@ -127,6 +128,7 @@ class TestNullCoalescing extends Test { eq(arr.length, 3); for (i => v in [1, 2, 3]) eq(arr[i], v); + #end var b:B = cast null; var c:C = cast null; From ce196848d79c130ccdb58098bbc5d34a39037be1 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 13 Dec 2023 17:08:15 +0100 Subject: [PATCH 027/184] [ci,cs] workaround random output mixup for csTwoLibs test CI sometimes (3 times over 30 runs when I measured) ends up mixing up dll output of this test, and tries to compile (natively) code compiled both with and without -D no-root Clearing output folder between runs seems to make the problem disappear --- tests/misc/cs/csTwoLibs/compile-1.hxml | 2 ++ tests/misc/cs/csTwoLibs/compile-2.hxml | 2 ++ tests/misc/cs/csTwoLibs/compile-3.hxml | 2 ++ tests/misc/cs/csTwoLibs/compile-4.hxml | 2 ++ 4 files changed, 8 insertions(+) diff --git a/tests/misc/cs/csTwoLibs/compile-1.hxml b/tests/misc/cs/csTwoLibs/compile-1.hxml index e16eb826653..8d1ded25b7e 100644 --- a/tests/misc/cs/csTwoLibs/compile-1.hxml +++ b/tests/misc/cs/csTwoLibs/compile-1.hxml @@ -1,3 +1,5 @@ +--cmd rm -rf bin +--next cs.Boot --dce no -cs bin/haxeboot diff --git a/tests/misc/cs/csTwoLibs/compile-2.hxml b/tests/misc/cs/csTwoLibs/compile-2.hxml index 8fa15b83804..d068487ca42 100644 --- a/tests/misc/cs/csTwoLibs/compile-2.hxml +++ b/tests/misc/cs/csTwoLibs/compile-2.hxml @@ -1,3 +1,5 @@ +--cmd rm -rf bin +--next cs.Boot --dce no -cs bin/haxeboot diff --git a/tests/misc/cs/csTwoLibs/compile-3.hxml b/tests/misc/cs/csTwoLibs/compile-3.hxml index 5d7896d1b44..71373e56fc9 100644 --- a/tests/misc/cs/csTwoLibs/compile-3.hxml +++ b/tests/misc/cs/csTwoLibs/compile-3.hxml @@ -1,3 +1,5 @@ +--cmd rm -rf bin +--next cs.Boot --dce no -cs bin/haxeboot diff --git a/tests/misc/cs/csTwoLibs/compile-4.hxml b/tests/misc/cs/csTwoLibs/compile-4.hxml index a256a141bfa..57da36133b0 100644 --- a/tests/misc/cs/csTwoLibs/compile-4.hxml +++ b/tests/misc/cs/csTwoLibs/compile-4.hxml @@ -1,3 +1,5 @@ +--cmd rm -rf bin +--next cs.Boot --dce no -cs bin/haxeboot From 13666860eceb09a98269d07d97ebbcc6abb6405f Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 14 Dec 2023 13:55:14 +0100 Subject: [PATCH 028/184] [analyzer] don't recursively check enum values when const propagating closes #11429 --- src/optimization/analyzer.ml | 4 ++-- tests/unit/src/unit/issues/Issue11429.hx | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 tests/unit/src/unit/issues/Issue11429.hx diff --git a/src/optimization/analyzer.ml b/src/optimization/analyzer.ml index c788f950000..b170c828374 100644 --- a/src/optimization/analyzer.ml +++ b/src/optimization/analyzer.ml @@ -375,11 +375,11 @@ module ConstPropagation = DataFlow(struct let top = Top let bottom = Bottom - let rec equals lat1 lat2 = match lat1,lat2 with + let equals lat1 lat2 = match lat1,lat2 with | Top,Top | Bottom,Bottom -> true | Const ct1,Const ct2 -> ct1 = ct2 | Null t1,Null t2 -> t1 == t2 - | EnumValue(i1,tl1),EnumValue(i2,tl2) -> i1 = i2 && safe_for_all2 equals tl1 tl2 + | EnumValue(i1,[]),EnumValue(i2,[]) -> i1 = i2 | ModuleType(mt1,_),ModuleType (mt2,_) -> mt1 == mt2 | _ -> false diff --git a/tests/unit/src/unit/issues/Issue11429.hx b/tests/unit/src/unit/issues/Issue11429.hx new file mode 100644 index 00000000000..9383f9d74c7 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11429.hx @@ -0,0 +1,19 @@ +package unit.issues; + +private enum Foo { + FooRec(foo:Foo); +} + +class Issue11429 extends Test { + function test() { + blowUp([]); + utest.Assert.pass(); + } + + public static function blowUp(arr:Array) { + var qp = FooRec(arr.pop()); + while (arr.length > 0) { + qp = FooRec(qp); + } + } +} From af369a7765122650e47ef3768c982ae786167523 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Sat, 16 Dec 2023 10:02:19 +0100 Subject: [PATCH 029/184] [typer] type operator lhs against expected type (#11428) see #10981 --- src/typing/operators.ml | 4 ++++ tests/unit/src/unit/issues/Issue10981.hx | 15 +++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/unit/src/unit/issues/Issue10981.hx diff --git a/src/typing/operators.ml b/src/typing/operators.ml index bc5bf5b1cd9..c297650c1a3 100644 --- a/src/typing/operators.ml +++ b/src/typing/operators.ml @@ -630,6 +630,10 @@ let type_non_assign_op ctx op e1 e2 is_assign_op abstract_overload_only with_typ WithType.value in let e1 = type_expr ctx e1 wt in + let e1 = match wt with + | WithType.WithType(t,_) -> AbstractCast.cast_or_unify ctx t e1 e1.epos + | _ -> e1 + in let result = if abstract_overload_only then begin let e2 = type_binop_rhs ctx op e1 e2 is_assign_op with_type p in try_abstract_binop_overloads ctx op e1 e2 is_assign_op p diff --git a/tests/unit/src/unit/issues/Issue10981.hx b/tests/unit/src/unit/issues/Issue10981.hx new file mode 100644 index 00000000000..8782e452d55 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue10981.hx @@ -0,0 +1,15 @@ +package unit.issues; + +import haxe.EnumFlags; + +private enum E { + A; + B; +} + +class Issue10981 extends Test { + function test() { + var flags:EnumFlags = A | B; + eq(3, flags.toInt()); + } +} From 3e721f01d761557270e1907b75220d7fcc6553ad Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Sat, 16 Dec 2023 10:43:57 +0100 Subject: [PATCH 030/184] [ci] lock utest version --- tests/RunCi.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/RunCi.hx b/tests/RunCi.hx index 6e48451d3e3..4016da62e1b 100644 --- a/tests/RunCi.hx +++ b/tests/RunCi.hx @@ -37,7 +37,7 @@ class RunCi { infoMsg('test $test'); try { changeDirectory(unitDir); - haxelibInstallGit("haxe-utest", "utest", "--always"); + haxelibInstallGit("haxe-utest", "utest", "424a7182a93057730fada54b9d27d90b3cb7065c", "--always"); var args = switch (ci) { case null: From 15731ea67231d57e102a8fbfe729ffc23106cfde Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sat, 16 Dec 2023 17:09:22 +0100 Subject: [PATCH 031/184] fixed pos_path is sometimes null_pos whereas pos_full is not (close #11431) --- src/typing/typeload.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typing/typeload.ml b/src/typing/typeload.ml index 694d8edeb42..e748a1d5271 100644 --- a/src/typing/typeload.ml +++ b/src/typing/typeload.ml @@ -429,7 +429,7 @@ and load_instance' ctx ptp get_params = if t.tparams <> [] then raise_typing_error ("Class type parameter " ^ t.tname ^ " can't have parameters") ptp.pos_full; pt with Not_found -> - let mt = load_type_def ctx ptp.pos_path t in + let mt = load_type_def ctx (if ptp.pos_path == null_pos then ptp.pos_full else ptp.pos_path) t in let info = ctx.g.get_build_info ctx mt ptp.pos_full in if info.build_path = ([],"Dynamic") then match t.tparams with | [] -> t_dynamic From 45268f70f737a7b212116ddd89ab9b29aec1586e Mon Sep 17 00:00:00 2001 From: Zeta <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Mon, 18 Dec 2023 17:32:49 +0100 Subject: [PATCH 032/184] [tests] Force link mbedtls@2 on macOS. (#11435) --- tests/runci/targets/Hl.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/runci/targets/Hl.hx b/tests/runci/targets/Hl.hx index 07ff7999687..7bf6f207ae8 100644 --- a/tests/runci/targets/Hl.hx +++ b/tests/runci/targets/Hl.hx @@ -39,6 +39,7 @@ class Hl { case "Mac": runNetworkCommand("brew", ["update", '--preinstall']); runNetworkCommand("brew", ["bundle", '--file=${hlSrc}/Brewfile']); + runNetworkCommand("brew", ["link", "mbedtls@2", "--force"]); case "Windows": //pass } From 541259e4c3b93e96a6f2b826d512c41b93fe5de0 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Tue, 19 Dec 2023 19:47:48 +0100 Subject: [PATCH 033/184] Internal type parameter changes (#11436) * use tclass equality instead of Type.t * change type parameter handling * fix gencommon a bit * remove redundant name * fix gencommon param cloning * make sure lazies are resolved at some point --- src/codegen/codegen.ml | 9 +- src/codegen/gencommon/castDetect.ml | 2 +- src/codegen/gencommon/closuresToClass.ml | 15 +- src/codegen/gencommon/dynamicFieldAccess.ml | 8 +- src/codegen/gencommon/enumToClass.ml | 4 +- src/codegen/gencommon/gencommon.ml | 7 +- .../gencommon/overloadingConstructor.ml | 17 ++- src/codegen/gencommon/realTypeParams.ml | 15 +- src/codegen/gencommon/renameTypeParameters.ml | 14 +- src/codegen/overloads.ml | 9 +- src/context/abstractCast.ml | 7 +- src/context/display/displayFields.ml | 11 +- src/context/display/displayToplevel.ml | 6 +- src/context/typecore.ml | 4 +- src/core/display/completionItem.ml | 14 +- src/core/json/genjson.ml | 14 +- src/core/tFunctions.ml | 34 +++-- src/core/tPrinting.ml | 28 ++-- src/core/tType.ml | 4 +- src/core/tUnification.ml | 37 ++--- src/filters/filtersCommon.ml | 7 +- src/generators/gencs.ml | 11 +- src/generators/genhl.ml | 10 +- src/generators/genjava.ml | 13 +- src/generators/genjvm.ml | 22 ++- src/generators/genlua.ml | 2 +- src/generators/genswf.ml | 4 +- src/generators/genswf9.ml | 4 +- src/macro/macroApi.ml | 42 +----- src/optimization/dce.ml | 8 +- src/optimization/inline.ml | 2 +- src/typing/fields.ml | 4 +- src/typing/generic.ml | 35 +++-- src/typing/operators.ml | 4 +- src/typing/typeload.ml | 136 +++++++++--------- src/typing/typeloadCheck.ml | 43 +++--- src/typing/typer.ml | 4 +- src/typing/typerBase.ml | 4 +- src/typing/typerDisplay.ml | 6 +- 39 files changed, 279 insertions(+), 341 deletions(-) diff --git a/src/codegen/codegen.ml b/src/codegen/codegen.ml index b8d363ab4bc..5893255443e 100644 --- a/src/codegen/codegen.ml +++ b/src/codegen/codegen.ml @@ -122,8 +122,13 @@ let fix_override com c f fd = (* Flash generates type parameters with a single constraint as that constraint type, so we have to detect this case and change the variable (issue #2712). *) begin match follow v.v_type with - | TInst({cl_kind = KTypeParameter [tc]} as cp,_) when com.platform = Flash -> - if List.exists (fun tp -> tp.ttp_name = (snd cp.cl_path)) c.cl_params then raise (Unify_error []) + | TInst({cl_kind = KTypeParameter ttp} as cp,_) when com.platform = Flash -> + begin match get_constraints ttp with + | [tc] -> + if List.exists (fun tp -> tp.ttp_name = (snd cp.cl_path)) c.cl_params then raise (Unify_error []) + | _ -> + () + end | _ -> () end; diff --git a/src/codegen/gencommon/castDetect.ml b/src/codegen/gencommon/castDetect.ml index af2350b9471..f301bf4f163 100644 --- a/src/codegen/gencommon/castDetect.ml +++ b/src/codegen/gencommon/castDetect.ml @@ -290,7 +290,7 @@ let do_unsafe_cast gen from_t to_t e = | _ -> raise Not_found in match gen.gfollow#run_f from_t, gen.gfollow#run_f to_t with - | TInst({ cl_kind = KTypeParameter tl },_), t2 when List.exists (fun t -> unifies t t2) tl -> + | TInst({ cl_kind = KTypeParameter ttp },_), t2 when List.exists (fun t -> unifies t t2) (get_constraints ttp) -> mk_cast to_t (mk_cast t_dynamic e) | from_t, to_t when gen.gspecial_needs_cast to_t from_t -> mk_cast to_t e diff --git a/src/codegen/gencommon/closuresToClass.ml b/src/codegen/gencommon/closuresToClass.ml index 7bc2b6cca69..d35bf652194 100644 --- a/src/codegen/gencommon/closuresToClass.ml +++ b/src/codegen/gencommon/closuresToClass.ml @@ -289,10 +289,7 @@ let rec get_type_params acc t = get_type_params acc ( Abstract.get_underlying_type a pl) | TAnon a -> PMap.fold (fun cf acc -> - let params = List.map (fun tp -> match follow tp.ttp_type with - | TInst(c,_) -> c - | _ -> die "" __LOC__) cf.cf_params - in + let params = List.map (fun tp -> tp.ttp_class) cf.cf_params in List.filter (fun t -> not (List.memq t params)) (get_type_params acc cf.cf_type) ) a.a_fields acc | TType(_, []) @@ -396,7 +393,7 @@ let configure gen ft = in (*let cltypes = List.map (fun cl -> (snd cl.cl_path, TInst(map_param cl, []) )) tparams in*) - let cltypes = List.map (fun cl -> mk_type_param (snd cl.cl_path) (TInst(cl, [])) None) tparams in + let cltypes = List.map (fun cl -> mk_type_param cl None None) tparams in (* create a new class that extends abstract function class, with a ctor implementation that will setup all captured variables *) let cfield = match gen.gcurrent_classfield with @@ -613,14 +610,10 @@ let configure gen ft = let monos = List.map (fun t -> apply_params types (List.map (fun _ -> t_dynamic) types) t) monos in - let same_cl t1 t2 = match follow t1, follow t2 with - | TInst(c,_), TInst(c2,_) -> c == c2 - | _ -> false - in - let passoc = List.map2 (fun tp m -> tp.ttp_type,m) types monos in + let passoc = List.map2 (fun tp m -> tp.ttp_class,m) types monos in let cltparams = List.map (fun tp -> try - snd (List.find (fun (t2,_) -> same_cl tp.ttp_type t2) passoc) + snd (List.find (fun (t2,_) -> tp.ttp_class == t2) passoc) with | Not_found -> tp.ttp_type) cls.cl_params in { e with eexpr = TNew(cls, cltparams, List.rev captured) } diff --git a/src/codegen/gencommon/dynamicFieldAccess.ml b/src/codegen/gencommon/dynamicFieldAccess.ml index 408c9b9816c..78fc88c39ba 100644 --- a/src/codegen/gencommon/dynamicFieldAccess.ml +++ b/src/codegen/gencommon/dynamicFieldAccess.ml @@ -58,8 +58,8 @@ let priority = solve_deps name [DAfter DynamicOperators.priority] *) let configure gen (is_dynamic:texpr->Type.tfield_access->bool) (change_expr:texpr->texpr->string->texpr option->bool->texpr) (call_expr:texpr->texpr->string->texpr list->texpr) = let is_nondynamic_tparam fexpr f = match follow fexpr.etype with - | TInst({ cl_kind = KTypeParameter(tl) }, _) -> - List.exists (fun t -> not (is_dynamic { fexpr with etype = t } f)) tl + | TInst({ cl_kind = KTypeParameter(ttp) }, _) -> + List.exists (fun t -> not (is_dynamic { fexpr with etype = t } f)) (get_constraints ttp) | _ -> false in @@ -68,8 +68,8 @@ let configure gen (is_dynamic:texpr->Type.tfield_access->bool) (change_expr:texp (* class types *) | TField(fexpr, f) when is_nondynamic_tparam fexpr f -> (match follow fexpr.etype with - | TInst( ({ cl_kind = KTypeParameter(tl) } as tp_cl), tp_tl) -> - let t = apply_params tp_cl.cl_params tp_tl (List.find (fun t -> not (is_dynamic { fexpr with etype = t } f)) tl) in + | TInst( ({ cl_kind = KTypeParameter(ttp) } as tp_cl), tp_tl) -> + let t = apply_params tp_cl.cl_params tp_tl (List.find (fun t -> not (is_dynamic { fexpr with etype = t } f)) (get_constraints ttp)) in { e with eexpr = TField(mk_cast t (run fexpr), f) } | _ -> Globals.die "" __LOC__) diff --git a/src/codegen/gencommon/enumToClass.ml b/src/codegen/gencommon/enumToClass.ml index 229256a12e9..4c1051d43f7 100644 --- a/src/codegen/gencommon/enumToClass.ml +++ b/src/codegen/gencommon/enumToClass.ml @@ -102,7 +102,7 @@ struct | _ -> ()); let c_types = if handle_type_params then - List.map (fun tp -> {tp with ttp_type=TInst (map_param (get_cl_t tp.ttp_type), [])}) en.e_params + List.map clone_param en.e_params else [] in @@ -120,7 +120,7 @@ struct | TFun(params,ret) -> let dup_types = if handle_type_params then - List.map (fun tp -> {tp with ttp_type = TInst (map_param (get_cl_t tp.ttp_type), [])}) en.e_params + List.map clone_param en.e_params else [] in diff --git a/src/codegen/gencommon/gencommon.ml b/src/codegen/gencommon/gencommon.ml index 24e0b8c97f1..4dc998fc58e 100644 --- a/src/codegen/gencommon/gencommon.ml +++ b/src/codegen/gencommon/gencommon.ml @@ -1137,11 +1137,14 @@ let mk_class_field ?(static = false) name t public pos kind params = (* this helper just duplicates the type parameter class, which is assumed that cl is. *) (* This is so we can use class parameters on function parameters, without running the risk of name clash *) (* between both *) -let map_param cl = +let clone_param ttp = + let cl = ttp.ttp_class in let ret = mk_class cl.cl_module (fst cl.cl_path, snd cl.cl_path ^ "_c") cl.cl_pos null_pos in ret.cl_implements <- cl.cl_implements; ret.cl_kind <- cl.cl_kind; - ret + let ttp = mk_type_param ret ttp.ttp_default ttp.ttp_constraints in + ret.cl_kind <- KTypeParameter ttp; + ttp let get_cl_t t = match follow t with | TInst (cl,_) -> cl | _ -> die "" __LOC__ diff --git a/src/codegen/gencommon/overloadingConstructor.ml b/src/codegen/gencommon/overloadingConstructor.ml index db11eecf471..91fc5c6af5b 100644 --- a/src/codegen/gencommon/overloadingConstructor.ml +++ b/src/codegen/gencommon/overloadingConstructor.ml @@ -113,16 +113,15 @@ let create_static_ctor com ~empty_ctor_expr cl ctor follow_type = | false -> let static_ctor_name = make_static_ctor_name cl in (* create the static constructor *) - let ctor_types = List.map (fun tp -> {tp with ttp_type = TInst(map_param (get_cl_t tp.ttp_type), [])}) cl.cl_params in + let ctor_types = List.map clone_param cl.cl_params in let ctor_type_params = extract_param_types ctor_types in - List.iter (function {ttp_type=TInst(c,[])} -> ( - match c.cl_kind with - | KTypeParameter (hd :: tail) -> - let before = hd :: tail in - let after = List.map (apply_params cl.cl_params ctor_type_params) (before) in - c.cl_kind <- KTypeParameter(after) - | _ -> ()) - | _ -> ()) ctor_types; + List.iter (fun ttp -> match get_constraints ttp with + | [] -> + () + | before -> + let after = List.map (apply_params cl.cl_params ctor_type_params) before in + ttp.ttp_constraints <- Some (lazy after) + ) ctor_types; let me = alloc_var "__hx_this" (TInst(cl, extract_param_types ctor_types)) in add_var_flag me VCaptured; diff --git a/src/codegen/gencommon/realTypeParams.ml b/src/codegen/gencommon/realTypeParams.ml index bac5e5b60eb..5ed9d19c339 100644 --- a/src/codegen/gencommon/realTypeParams.ml +++ b/src/codegen/gencommon/realTypeParams.ml @@ -308,10 +308,9 @@ let set_hxgeneric gen md = if not ret then begin match md with | TClassDecl c -> - let set_hxgeneric tp = match follow tp.ttp_type with - | TInst(c,_) -> - c.cl_meta <- (Meta.NativeGeneric, [], c.cl_pos) :: c.cl_meta - | _ -> () + let set_hxgeneric tp = + let c = tp.ttp_class in + c.cl_meta <- (Meta.NativeGeneric, [], c.cl_pos) :: c.cl_meta in List.iter set_hxgeneric c.cl_params; let rec handle_field cf = @@ -400,7 +399,7 @@ struct let rec loop curcls params level reverse_params = if (level <> 0 || (has_class_flag curcls CInterface) || (has_class_flag curcls CAbstract) ) && params <> [] && is_hxgeneric (TClassDecl curcls) then begin - let cparams = List.map (fun tp -> {tp with ttp_type=TInst (map_param (get_cl_t tp.ttp_type), [])}) curcls.cl_params in + let cparams = List.map clone_param curcls.cl_params in let name = get_cast_name curcls in if not (PMap.mem name cl.cl_fields) then begin let reverse_params = List.map (apply_params curcls.cl_params params) reverse_params in @@ -459,7 +458,7 @@ struct let create_cast_cfield gen cl name = reset_temps(); let basic = gen.gcon.basic in - let cparams = List.map (fun tp -> {tp with ttp_type = TInst (map_param (get_cl_t tp.ttp_type), [])}) cl.cl_params in + let cparams = List.map clone_param cl.cl_params in let cfield = mk_class_field name (TFun([], t_dynamic)) false cl.cl_pos (Method MethNormal) cparams in let params = extract_param_types cparams in @@ -590,7 +589,7 @@ struct let create_static_cast_cf gen iface cf = let p = iface.cl_pos in let basic = gen.gcon.basic in - let cparams = List.map (fun tp -> {tp with ttp_name = "To_" ^ tp.ttp_name;ttp_type = TInst (map_param (get_cl_t tp.ttp_type), [])}) cf.cf_params in + let cparams = List.map clone_param cf.cf_params in let me_type = TInst(iface,[]) in let cfield = mk_class_field ~static:true "__hx_cast" (TFun(["me",false,me_type], t_dynamic)) false iface.cl_pos (Method MethNormal) (cparams) in let params = extract_param_types cparams in @@ -637,7 +636,7 @@ struct let implement_stub_cast cthis iface tl = let name = get_cast_name iface in if not (PMap.mem name cthis.cl_fields) then begin - let cparams = List.map (fun tp -> {tp with ttp_name = "To_" ^ tp.ttp_name;ttp_type = TInst(map_param (get_cl_t tp.ttp_type), [])}) iface.cl_params in + let cparams = List.map clone_param iface.cl_params in let field = mk_class_field name (TFun([],t_dynamic)) false iface.cl_pos (Method MethNormal) cparams in let this = { eexpr = TConst TThis; etype = TInst(cthis, extract_param_types cthis.cl_params); epos = cthis.cl_pos } in field.cf_expr <- Some { diff --git a/src/codegen/gencommon/renameTypeParameters.ml b/src/codegen/gencommon/renameTypeParameters.ml index 3ec5b2f104e..dd3e0cbfbf6 100644 --- a/src/codegen/gencommon/renameTypeParameters.ml +++ b/src/codegen/gencommon/renameTypeParameters.ml @@ -41,22 +41,16 @@ let run types = end else found_types := PMap.add name true !found_types in - let get_cls t = - match follow t with - | TInst(cl,_) -> cl - | _ -> Globals.die "" __LOC__ - in - let iter_types tp = - let cls = get_cls tp.ttp_type in + let cls = tp.ttp_class in let orig = cls.cl_path in check_type (snd orig) (fun name -> cls.cl_path <- (fst orig, name)) in let save_params save params = List.fold_left (fun save tp -> - let cls = get_cls tp.ttp_type in - (cls.cl_path,tp.ttp_type) :: save) save params + let cls = tp.ttp_class in + (cls.cl_path,tp.ttp_class) :: save) save params in List.iter (function @@ -82,7 +76,7 @@ let run types = cl.cl_restore <- (fun () -> res(); List.iter (fun (path,t) -> - let cls = get_cls t in + let cls = t in cls.cl_path <- path) save ); end diff --git a/src/codegen/overloads.ml b/src/codegen/overloads.ml index dfba3040a32..3657e537f31 100644 --- a/src/codegen/overloads.ml +++ b/src/codegen/overloads.ml @@ -13,13 +13,10 @@ let same_overload_args ?(get_vmtype) t1 t2 f1 f2 = | [],[] -> true | tp1 :: params1,tp2 :: params2 -> - let constraints_equal t1 t2 = match follow t1,follow t2 with - | TInst({cl_kind = KTypeParameter tl1},_),TInst({cl_kind = KTypeParameter tl2},_) -> - Ast.safe_for_all2 f_eq tl1 tl2 - | _ -> - false + let constraints_equal ttp1 ttp2 = + Ast.safe_for_all2 f_eq (get_constraints ttp2) (get_constraints ttp2) in - tp1.ttp_name = tp2.ttp_name && constraints_equal tp1.ttp_type tp2.ttp_type && loop params1 params2 + tp1.ttp_name = tp2.ttp_name && constraints_equal tp1 tp2 && loop params1 params2 | [],_ | _,[] -> false diff --git a/src/context/abstractCast.ml b/src/context/abstractCast.ml index 4a066a72121..62afbfc23ec 100644 --- a/src/context/abstractCast.ml +++ b/src/context/abstractCast.ml @@ -119,10 +119,11 @@ let prepare_array_access_field ctx a pl cf p = let monos = List.map (fun _ -> spawn_monomorph ctx p) cf.cf_params in let map t = apply_params a.a_params pl (apply_params cf.cf_params monos t) in let check_constraints () = - List.iter2 (fun m tp -> match follow tp.ttp_type with - | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] -> + List.iter2 (fun m ttp -> match get_constraints ttp with + | [] -> + () + | constr -> List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> Type.unify m (map tc) ) constr - | _ -> () ) monos cf.cf_params; in let get_ta() = diff --git a/src/context/display/displayFields.ml b/src/context/display/displayFields.ml index 6c576642e66..929ea7b4d62 100644 --- a/src/context/display/displayFields.ml +++ b/src/context/display/displayFields.ml @@ -56,10 +56,11 @@ let collect_static_extensions ctx items e p = | TFun((_,_,t) :: args, ret) -> begin try let e = TyperBase.unify_static_extension ctx {e with etype = dup e.etype} t p in - List.iter2 (fun m tp -> match follow tp.ttp_type with - | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] -> + List.iter2 (fun m ttp -> match get_constraints ttp with + | [] -> + () + | constr -> List.iter (fun tc -> unify_raise m (map tc) e.epos) constr - | _ -> () ) monos f.cf_params; if not (can_access ctx c f true) || follow e.etype == t_dynamic && follow t != t_dynamic then acc @@ -157,9 +158,9 @@ let collect ctx e_ast e dk with_type p = List.fold_left fold_constraints items l in fold_constraints items (Monomorph.classify_down_constraints m) - | TInst ({cl_kind = KTypeParameter tl},_) -> + | TInst ({cl_kind = KTypeParameter ttp},_) -> (* Type parameters can access the fields of their constraints *) - List.fold_left (fun acc t -> loop acc t) items tl + List.fold_left (fun acc t -> loop acc t) items (get_constraints ttp) | TInst(c0,tl) -> (* For classes, browse the hierarchy *) let fields = TClass.get_all_fields c0 tl in diff --git a/src/context/display/displayToplevel.ml b/src/context/display/displayToplevel.ml index 86bbcff00fd..a7c07716429 100644 --- a/src/context/display/displayToplevel.ml +++ b/src/context/display/displayToplevel.ml @@ -449,10 +449,8 @@ let collect ctx tk with_type sort = end; (* type params *) - List.iter (fun tp -> match follow tp.ttp_type with - | TInst(c,_) -> - add (make_ci_type_param c (tpair tp.ttp_type)) (Some (snd c.cl_path)) - | _ -> die "" __LOC__ + List.iter (fun tp -> + add (make_ci_type_param tp.ttp_class (tpair tp.ttp_type)) (Some (snd tp.ttp_class.cl_path)) ) ctx.type_params; (* module types *) diff --git a/src/context/typecore.ml b/src/context/typecore.ml index 7ec1d34ccab..f0fcded97f9 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -616,8 +616,8 @@ let can_access ctx c cf stat = loop c (* access is also allowed of we access a type parameter which is constrained to our (base) class *) || (match c.cl_kind with - | KTypeParameter tl -> - List.exists (fun t -> match follow t with TInst(c,_) -> loop c | _ -> false) tl + | KTypeParameter ttp -> + List.exists (fun t -> match follow t with TInst(c,_) -> loop c | _ -> false) (get_constraints ttp) | _ -> false) || (Meta.has Meta.PrivateAccess ctx.meta) diff --git a/src/core/display/completionItem.ml b/src/core/display/completionItem.ml index 16f47d54c01..b9032ece4d8 100644 --- a/src/core/display/completionItem.ml +++ b/src/core/display/completionItem.ml @@ -223,16 +223,14 @@ module CompletionModuleType = struct in let is_extern,is_final,is_abstract,kind,ctor = ctor_info mt in let infos = t_infos mt in - let convert_type_param tp = match follow tp.ttp_type with - | TInst(c,_) -> { - tp_name = tp.ttp_name,null_pos; + let convert_type_param ttp = + { + tp_name = ttp.ttp_name,null_pos; tp_params = []; tp_constraints = None; (* TODO? *) tp_default = None; (* TODO? *) - tp_meta = c.cl_meta + tp_meta = ttp.ttp_class.cl_meta } - | _ -> - die "" __LOC__ in { pack = fst infos.mt_path; @@ -784,11 +782,11 @@ let to_json ctx index item = | ITExpression e -> "Expression",generate_texpr ctx e | ITTypeParameter c -> begin match c.cl_kind with - | KTypeParameter tl -> + | KTypeParameter ttp -> "TypeParameter",jobject [ "name",jstring (snd c.cl_path); "meta",generate_metadata ctx c.cl_meta; - "constraints",jlist (generate_type ctx) tl; + "constraints",jlist (generate_type ctx) (get_constraints ttp); ] | _ -> die "" __LOC__ end diff --git a/src/core/json/genjson.ml b/src/core/json/genjson.ml index 3006c2f3e7a..a6b1b9d529e 100644 --- a/src/core/json/genjson.ml +++ b/src/core/json/genjson.ml @@ -276,15 +276,11 @@ and generate_type_path_with_params ctx mpath tpath tl meta = (* type parameter *) -and generate_type_parameter ctx tp = - let generate_constraints () = match follow tp.ttp_type with - | TInst({cl_kind = KTypeParameter tl},_) -> generate_types ctx tl - | _ -> die "" __LOC__ - in +and generate_type_parameter ctx ttp = jobject [ - "name",jstring tp.ttp_name; - "constraints",generate_constraints (); - "defaultType",jopt (generate_type ctx) tp.ttp_default; + "name",jstring ttp.ttp_name; + "constraints",generate_types ctx (get_constraints ttp); + "defaultType",jopt (generate_type ctx) ttp.ttp_default; ] (* texpr *) @@ -602,7 +598,7 @@ let generate_class ctx c = let generate_class_kind ck = let ctor,args = match ck with | KNormal -> "KNormal",None - | KTypeParameter tl -> "KTypeParameter",Some (generate_types ctx tl) + | KTypeParameter ttp -> "KTypeParameter",Some (generate_types ctx (get_constraints ttp)) | KExpr e -> "KExpr",Some (generate_expr ctx e) | KGeneric -> "KGeneric",None | KGenericInstance(c,tl) -> "KGenericInstance",Some (generate_type_path_with_params ctx c.cl_module.m_path c.cl_path tl c.cl_meta) diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index f9aec9853e3..9f3240a37f0 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -373,15 +373,11 @@ let apply_params ?stack cparams params t = 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 - | tp :: l1 , t2 :: l2 -> (tp.ttp_type,t2) :: loop l1 l2 + | ttp :: l1 , t2 :: l2 -> (ttp.ttp_class,t2) :: loop l1 l2 | _ -> die "" __LOC__ in let subst = loop cparams params in let rec loop t = - try - List.assq t subst - with Not_found -> match t with | TMono r -> (match r.tm_type with @@ -444,6 +440,12 @@ let apply_params ?stack cparams params t = (match tl with | [] -> t | _ -> TAbstract (a,List.map loop tl)) + | TInst ({cl_kind = KTypeParameter _} as c,[]) -> + begin try + List.assq c subst + with Not_found -> + t + end | TInst (c,tl) -> (match tl with | [] -> @@ -653,9 +655,11 @@ let lookup_param n l = in loop l -let mk_type_param n t def = { - ttp_name = n; - ttp_type = t; +let mk_type_param c def constraints = { + ttp_name = snd c.cl_path; + ttp_type = TInst(c,[]); + ttp_class = c; + ttp_constraints = constraints; ttp_default = def; } @@ -687,13 +691,19 @@ let tconst_to_const = function | TThis -> Ident "this" | TSuper -> Ident "super" +let get_constraints ttp = match ttp.ttp_constraints with + | None -> + [] + | Some r -> + Lazy.force r + let has_ctor_constraint c = match c.cl_kind with - | KTypeParameter tl -> + | KTypeParameter ttp -> List.exists (fun t -> match follow t with | TAnon a when PMap.mem "new" a.a_fields -> true | TAbstract({a_path=["haxe"],"Constructible"},_) -> true | _ -> false - ) tl; + ) (get_constraints ttp); | _ -> false (* ======= Field utility ======= *) @@ -741,7 +751,7 @@ let rec raw_class_field build_type c tl i = c2, apply_params c.cl_params tl t , f with Not_found -> match c.cl_kind with - | KTypeParameter tl -> + | KTypeParameter ttp -> let rec loop = function | [] -> raise Not_found @@ -762,7 +772,7 @@ let rec raw_class_field build_type c tl i = | _ -> loop ctl in - loop tl + loop (get_constraints ttp) | _ -> if not (has_class_flag c CInterface) then raise Not_found; (* diff --git a/src/core/tPrinting.ml b/src/core/tPrinting.ml index a7126d4d281..0757e7cda56 100644 --- a/src/core/tPrinting.ml +++ b/src/core/tPrinting.ml @@ -380,8 +380,8 @@ let s_types ?(sep = ", ") tl = let s_class_kind = function | KNormal -> "KNormal" - | KTypeParameter tl -> - Printf.sprintf "KTypeParameter [%s]" (s_types tl) + | KTypeParameter ttp -> + Printf.sprintf "KTypeParameter [%s]" (s_types (get_constraints ttp)) | KExpr _ -> "KExpr" | KGeneric -> @@ -441,19 +441,17 @@ module Printer = struct let s_metadata metadata = s_list " " s_metadata_entry metadata - let s_type_param tp = match follow tp.ttp_type with - | TInst({cl_kind = KTypeParameter tl1},tl2) -> - let s = match tl1 with - | [] -> tp.ttp_name - | _ -> Printf.sprintf "%s:%s" tp.ttp_name (String.concat " & " (List.map s_type tl1)) - in - begin match tp.ttp_default with - | None -> - s - | Some t -> - Printf.sprintf "%s = %s" s (s_type t) - end - | _ -> die "" __LOC__ + let s_type_param ttp = + let s = match (get_constraints ttp) with + | [] -> ttp.ttp_name + | tl1 -> Printf.sprintf "%s:%s" ttp.ttp_name (String.concat " & " (List.map s_type tl1)) + in + begin match ttp.ttp_default with + | None -> + s + | Some t -> + Printf.sprintf "%s = %s" s (s_type t) + end let s_type_params tl = s_list ", " s_type_param tl diff --git a/src/core/tType.ml b/src/core/tType.ml index f313959a78a..2a5e8fb2723 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -93,6 +93,8 @@ and tparams = t list and typed_type_param = { ttp_name : string; ttp_type : t; + ttp_class : tclass; + mutable ttp_constraints : t list Lazy.t option; ttp_default : t option; } @@ -232,7 +234,7 @@ and tclass_field = { and tclass_kind = | KNormal - | KTypeParameter of t list + | KTypeParameter of typed_type_param | KExpr of Ast.expr | KGeneric | KGenericInstance of tclass * tparams diff --git a/src/core/tUnification.ml b/src/core/tUnification.ml index 6335fd4a5d7..25bad0a5f81 100644 --- a/src/core/tUnification.ml +++ b/src/core/tUnification.ml @@ -260,13 +260,13 @@ module Monomorph = struct let spawn_constrained_monos map params = let checks = DynArray.create () in - let monos = List.map (fun tp -> + let monos = List.map (fun ttp -> let mono = create () in - begin match follow tp.ttp_type with - | TInst ({ cl_kind = KTypeParameter constr; cl_path = path },_) when constr <> [] -> - DynArray.add checks (mono,constr,s_type_path path) - | _ -> + begin match get_constraints ttp with + | [] -> () + | constr -> + DynArray.add checks (mono,constr,s_type_path ttp.ttp_class.cl_path) end; TMono mono ) params in @@ -695,12 +695,13 @@ let rec unify (uctx : unification_context) a b = loop cs (List.map (apply_params c.cl_params tl) tls) ) c.cl_implements || (match c.cl_kind with - | KTypeParameter pl -> List.exists (fun t -> - match follow t with - | TInst (cs,tls) -> loop cs (List.map (apply_params c.cl_params tl) tls) - | TAbstract(aa,tl) -> unifies_to uctx a b aa tl - | _ -> false - ) pl + | KTypeParameter ttp -> + List.exists (fun t -> + match follow t with + | TInst (cs,tls) -> loop cs (List.map (apply_params c.cl_params tl) tls) + | TAbstract(aa,tl) -> unifies_to uctx a b aa tl + | _ -> false + ) (get_constraints ttp) | _ -> false) in if not (loop c1 tl1) then error [cannot_unify a b] @@ -722,9 +723,9 @@ let rec unify (uctx : unification_context) a b = error (cannot_unify a b :: msg :: l)) | TInst (c,tl) , TAnon an -> if PMap.is_empty an.a_fields then (match c.cl_kind with - | KTypeParameter pl -> + | KTypeParameter ttp -> (* one of the constraints must unify with { } *) - if not (List.exists (fun t -> match follow t with TInst _ | TAnon _ -> true | _ -> false) pl) then error [cannot_unify a b] + if not (List.exists (fun t -> match follow t with TInst _ | TAnon _ -> true | _ -> false) (get_constraints ttp)) then error [cannot_unify a b] | _ -> ()); ignore(c.cl_build()); (try @@ -824,9 +825,9 @@ let rec unify (uctx : unification_context) a b = | TInst(c,tl),TAbstract({a_path = ["haxe"],"Constructible"},[t1]) -> begin try begin match c.cl_kind with - | KTypeParameter tl -> + | KTypeParameter ttp -> (* type parameters require an equal Constructible constraint *) - if not (List.exists (fun t -> match follow t with TAbstract({a_path = ["haxe"],"Constructible"},[t2]) -> type_iseq uctx t1 t2 | _ -> false) tl) then error [cannot_unify a b] + if not (List.exists (fun t -> match follow t with TAbstract({a_path = ["haxe"],"Constructible"},[t2]) -> type_iseq uctx t1 t2 | _ -> false) (get_constraints ttp)) then error [cannot_unify a b] | _ -> let _,t,cf = class_field c tl "new" in if not (has_class_field_flag cf CfPublic) then error [invalid_visibility "new"]; @@ -884,12 +885,12 @@ let rec unify (uctx : unification_context) a b = end | TAbstract (aa,tl), _ -> unify_to uctx a b aa tl - | TInst ({ cl_kind = KTypeParameter ctl } as c,pl), TAbstract (bb,tl) -> + | TInst ({ cl_kind = KTypeParameter ttp } as c,pl), TAbstract (bb,tl) -> (* one of the constraints must satisfy the abstract *) if not (List.exists (fun t -> let t = apply_params c.cl_params pl t in try unify uctx t b; true with Unify_error _ -> false - ) ctl) then unify_from uctx a b bb tl + ) (get_constraints ttp)) then unify_from uctx a b bb tl | _, TAbstract (bb,tl) -> unify_from uctx a b bb tl | _ , _ -> @@ -1136,7 +1137,7 @@ module UnifyMinT = struct let rec loop t = (match t with | TInst(cl, params) -> (match cl.cl_kind with - | KTypeParameter tl -> List.iter loop tl + | KTypeParameter ttp -> List.iter loop (get_constraints ttp) | _ -> ()); List.iter (fun (ic, ip) -> let t = apply_params cl.cl_params params (TInst (ic,ip)) in diff --git a/src/filters/filtersCommon.ml b/src/filters/filtersCommon.ml index cddaf31a10a..aa862dd718d 100644 --- a/src/filters/filtersCommon.ml +++ b/src/filters/filtersCommon.ml @@ -27,11 +27,8 @@ let rec is_removable_class c = (match c.cl_super with | Some (c,_) -> is_removable_class c | _ -> false) || - List.exists (fun tp -> match follow tp.ttp_type with - | TInst(c,_) -> - has_ctor_constraint c || Meta.has Meta.Const c.cl_meta - | _ -> - false + List.exists (fun tp -> + has_ctor_constraint tp.ttp_class || Meta.has Meta.Const tp.ttp_class.cl_meta ) c.cl_params) | KTypeParameter _ -> (* this shouldn't happen, have to investigate (see #4092) *) diff --git a/src/generators/gencs.ml b/src/generators/gencs.ml index cb474ed7168..08002d807ef 100644 --- a/src/generators/gencs.ml +++ b/src/generators/gencs.ml @@ -2009,18 +2009,17 @@ let generate con = let hxgen = is_hxgen (TClassDecl cl) in match cl_params with | (_ :: _) when not (erase_generics && is_hxgeneric (TClassDecl cl)) -> - let get_param_name t = match follow t with TInst(cl, _) -> snd cl.cl_path | _ -> die "" __LOC__ in let combination_error c1 c2 = gen.gcon.error ("The " ^ (get_constraint c1) ^ " constraint cannot be combined with the " ^ (get_constraint c2) ^ " constraint.") cl.cl_pos in - let params = sprintf "<%s>" (String.concat ", " (List.map (fun tp -> get_param_name tp.ttp_type) cl_params)) in + let params = sprintf "<%s>" (String.concat ", " (List.map (fun tp -> snd tp.ttp_class.cl_path) cl_params)) in let params_extends = if hxgen || not (Meta.has (Meta.NativeGen) cl.cl_meta) then [""] else List.fold_left (fun acc {ttp_name=name;ttp_type=t} -> - match run_follow gen t with - | TInst({cl_kind = KTypeParameter constraints}, _) when constraints <> [] -> + match t with + | TInst({cl_kind = KTypeParameter ttp} as c,_) when get_constraints ttp <> [] -> (* base class should come before interface constraints *) let base_class_constraints = ref [] in let other_constraints = List.fold_left (fun acc t -> @@ -2069,7 +2068,7 @@ let generate con = (* skip anything other *) | _ -> acc - ) [] constraints in + ) [] (get_constraints ttp ) in let s_constraints = (List.sort (* C# expects some ordering for built-in constraints: *) @@ -2085,7 +2084,7 @@ let generate con = ) (!base_class_constraints @ other_constraints)) in if s_constraints <> [] then - (sprintf " where %s : %s" (get_param_name t) (String.concat ", " (List.map get_constraint s_constraints)) :: acc) + (sprintf " where %s : %s" (snd c.cl_path) (String.concat ", " (List.map get_constraint s_constraints)) :: acc) else acc; | _ -> acc diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index cff859dcf9f..16b04edb53d 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -361,7 +361,7 @@ let make_debug ctx arr = let fake_tnull = {null_abstract with a_path = [],"Null"; - a_params = [{ttp_name = "T"; ttp_type = t_dynamic; ttp_default = None}]; + a_params = [mk_type_param null_class None None]; } let get_rec_cache ctx t none_callback not_found_callback = @@ -435,7 +435,7 @@ let rec to_type ?tref ctx t = HAbstract (name, alloc_string ctx name) | TInst (c,pl) -> (match c.cl_kind with - | KTypeParameter tl -> + | KTypeParameter ttp -> let rec loop = function | [] -> HDyn | t :: tl -> @@ -443,7 +443,7 @@ let rec to_type ?tref ctx t = | TInst (c,_) as t when not (has_class_flag c CInterface) -> to_type ?tref ctx t | _ -> loop tl in - loop tl + loop (get_constraints ttp) | _ -> class_type ~tref ctx c pl false) | TAbstract ({a_path = [],"Null"},[t1]) -> let t = to_type ?tref ctx t1 in @@ -2173,9 +2173,9 @@ and eval_expr ctx e = match follow t with | TFun (_,rt) -> (match follow rt with - | TInst({ cl_kind = KTypeParameter tl },_) -> + | TInst({ cl_kind = KTypeParameter ttp },_) -> (* don't allow if we have a constraint virtual, see hxbit.Serializer.getRef *) - not (List.exists (fun t -> match to_type ctx t with HVirtual _ -> true | _ -> false) tl) + not (List.exists (fun t -> match to_type ctx t with HVirtual _ -> true | _ -> false) (get_constraints ttp)) | _ -> false) | _ -> false diff --git a/src/generators/genjava.ml b/src/generators/genjava.ml index c80a388eb1d..71e199d6cb8 100644 --- a/src/generators/genjava.ml +++ b/src/generators/genjava.ml @@ -1904,17 +1904,8 @@ let generate con = | [] -> ("","") | _ -> - let params = sprintf "<%s>" (String.concat ", " (List.map (fun tp -> match follow tp.ttp_type with | TInst(cl, _) -> snd cl.cl_path | _ -> die "" __LOC__) cl_params)) in - let params_extends = List.fold_left (fun acc {ttp_name=name;ttp_type=t} -> - match run_follow gen t with - | TInst (cl, p) -> - (match cl.cl_implements with - | [] -> acc - | _ -> acc) (* TODO - | _ -> (sprintf " where %s : %s" name (String.concat ", " (List.map (fun (cl,p) -> path_param_s (TClassDecl cl) cl.cl_path p) cl.cl_implements))) :: acc ) *) - | _ -> trace (t_s null_pos t); die "" __LOC__ (* FIXME it seems that a cl_params will never be anything other than cl.cl_params. I'll take the risk and fail if not, just to see if that confirms *) - ) [] cl_params in - (params, String.concat " " params_extends) + let params = sprintf "<%s>" (String.concat ", " (List.map (fun tp -> snd tp.ttp_class.cl_path) cl_params)) in + (params, "") in let write_parts w parts = diff --git a/src/generators/genjvm.ml b/src/generators/genjvm.ml index 952f9920e19..7efa5cd4968 100644 --- a/src/generators/genjvm.ml +++ b/src/generators/genjvm.ml @@ -202,8 +202,11 @@ let rec jsignature_of_type gctx stack t = TObject((["haxe";"root"],"Array"),[TType(WNone,t)]) | TInst({cl_path = (["java"],"NativeArray")},[t]) -> TArray(jsignature_of_type t,None) - | TInst({cl_kind = KTypeParameter [t]},_) when t != t_dynamic -> jsignature_of_type t - | TInst({cl_kind = KTypeParameter _; cl_path = (_,name)},_) -> TTypeParameter name + | TInst({cl_kind = KTypeParameter ttp; cl_path = (_,name)},_) -> + begin match get_constraints ttp with + | [t] when t != t_dynamic -> jsignature_of_type t + | _ -> TTypeParameter name + end | TInst({cl_path = ["_Class"],"Class_Impl_"},_) -> java_class_sig | TInst({cl_path = ["_Enum"],"Enum_Impl_"},_) -> java_class_sig | TInst(c,tl) -> TObject(c.cl_path,List.map jtype_argument_of_type tl) @@ -2640,16 +2643,11 @@ class tclass_to_jvm gctx c = object(self) end method private generate_signature = - jc#set_type_parameters (List.map (fun tp -> - let jsigs = match follow tp.ttp_type with - | TInst({cl_kind = KTypeParameter tl},_) -> - List.map (fun t -> - get_boxed_type (jsignature_of_type gctx t) - ) tl - | _ -> - [] - in - (tp.ttp_name,jsigs) + jc#set_type_parameters (List.map (fun ttp -> + let jsigs = List.map (fun t -> + get_boxed_type (jsignature_of_type gctx t) + ) (get_constraints ttp) in + (ttp.ttp_name,jsigs) ) c.cl_params); match c.cl_super with | Some(c,tl) -> jc#set_super_parameters (List.map (jtype_argument_of_type gctx []) tl) diff --git a/src/generators/genlua.ml b/src/generators/genlua.ml index 79b2d703af4..3bbd314104e 100644 --- a/src/generators/genlua.ml +++ b/src/generators/genlua.ml @@ -281,7 +281,7 @@ let mk_mr_select com e ecall name = (* from genphp *) let rec is_string_type t = match follow t with - | TInst ({cl_kind = KTypeParameter constraints}, _) -> List.exists is_string_type constraints + | TInst ({cl_kind = KTypeParameter ttp}, _) -> List.exists is_string_type (get_constraints ttp) | TInst ({cl_path = ([], "String")}, _) -> true | TAnon a -> (match !(a.a_status) with diff --git a/src/generators/genswf.ml b/src/generators/genswf.ml index 4b44acc271c..c37632448a6 100644 --- a/src/generators/genswf.ml +++ b/src/generators/genswf.ml @@ -149,9 +149,7 @@ let build_dependencies t = | Some x -> add_inherit x); List.iter (fun tp -> (* add type-parameters constraints dependencies *) - match follow tp.ttp_type with - | TInst (c,_) -> List.iter add_inherit c.cl_implements - | _ -> () + List.iter add_inherit tp.ttp_class.cl_implements ) c.cl_params; List.iter add_inherit c.cl_implements; | TEnumDecl e when not e.e_extern -> diff --git a/src/generators/genswf9.ml b/src/generators/genswf9.ml index 4403837e1f0..b689717e5fc 100644 --- a/src/generators/genswf9.ml +++ b/src/generators/genswf9.ml @@ -238,8 +238,8 @@ let rec type_id ctx t = | _ -> def()) | TInst (c,_) -> (match c.cl_kind with - | KTypeParameter l -> - (match l with + | KTypeParameter ttp -> + (match get_constraints ttp with | [t] -> type_id ctx t | _ -> type_path ctx ([],"Object")) | _ -> diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index 78cb4d4286e..69871e0629d 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -1143,7 +1143,7 @@ and encode_method_kind m = and encode_class_kind k = let tag, pl = (match k with | KNormal -> 0, [] - | KTypeParameter pl -> 1, [encode_tparams pl] + | KTypeParameter ttp -> 1, [encode_tparams (get_constraints ttp)] (* TTPTODO *) | KModuleFields m -> 2, [encode_string (s_type_path m.m_path)] | KExpr e -> 3, [encode_expr e] | KGeneric -> 4, [] @@ -1443,14 +1443,6 @@ let decode_tconst c = | 6, [] -> TSuper | _ -> raise Invalid_expr -let decode_type_params v = - List.map (fun v -> - let name = decode_string (field v "name") in - let t = decode_type (field v "t") in - let default = opt decode_type (field v "defaultType") in - mk_type_param name t default - ) (decode_array v) - let decode_tvar v = (Obj.obj (decode_unsafe (field v "$")) : tvar) @@ -1479,31 +1471,6 @@ let decode_field_kind v = | 1, [m] -> Method (decode_method_kind m) | _ -> raise Invalid_expr -let decode_cfield v = - let public = decode_bool (field v "isPublic") in - let extern = decode_bool (field v "isExtern") in - let final = decode_bool (field v "isFinal") in - let abstract = decode_bool (field v "isAbstract") in - let cf = { - cf_name = decode_string (field v "name"); - cf_type = decode_type (field v "type"); - cf_pos = decode_pos (field v "pos"); - cf_name_pos = decode_pos (field v "namePos"); - cf_doc = decode_doc (field v "doc"); - cf_meta = []; (* TODO *) - cf_kind = decode_field_kind (field v "kind"); - cf_params = decode_type_params (field v "params"); - cf_expr = None; - cf_expr_unoptimized = None; - cf_overloads = decode_ref (field v "overloads"); - cf_flags = 0; - } in - if public then add_class_field_flag cf CfPublic; - if extern then add_class_field_flag cf CfExtern; - if final then add_class_field_flag cf CfFinal; - if abstract then add_class_field_flag cf CfAbstract; - cf - let decode_efield v = let rec get_enum t = match follow t with @@ -2304,10 +2271,13 @@ let macro_api ccom get_api = "apply_params", vfun3 (fun tpl tl t -> let tl = List.map decode_type (decode_array tl) in let tpl = List.map (fun v -> - let name = decode_string (field v "name") in let t = decode_type (field v "t") in let default = None in (* we don't care here *) - mk_type_param name t default + let c = match t with + | TInst(c,_) -> c + | _ -> die "" __LOC__ + in + mk_type_param c default None ) (decode_array tpl) in let rec map t = match t with | TInst({cl_kind = KTypeParameter _},_) -> diff --git a/src/optimization/dce.ml b/src/optimization/dce.ml index 498887fb14d..b4a1a7b4944 100644 --- a/src/optimization/dce.ml +++ b/src/optimization/dce.ml @@ -247,10 +247,10 @@ and mark_t dce p t = if not (List.exists (fun t2 -> Type.fast_eq t t2) dce.t_stack) then begin dce.t_stack <- t :: dce.t_stack; begin match follow t with - | TInst({cl_kind = KTypeParameter tl} as c,pl) -> + | TInst({cl_kind = KTypeParameter ttp} as c,pl) -> if not (Meta.has Meta.Used c.cl_meta) then begin c.cl_meta <- (mk_used_meta c.cl_pos) :: c.cl_meta; - List.iter (mark_t dce p) tl; + List.iter (mark_t dce p) (get_constraints ttp); end; List.iter (mark_t dce p) pl | TInst(c,pl) -> @@ -358,7 +358,7 @@ and field dce c n kind = end else match c.cl_super with Some (csup,_) -> field dce csup n kind | None -> raise Not_found with Not_found -> try match c.cl_kind with - | KTypeParameter tl -> + | KTypeParameter ttp -> let rec loop tl = match tl with | [] -> raise Not_found | TInst(c,_) :: cl -> @@ -366,7 +366,7 @@ and field dce c n kind = | t :: tl -> loop tl in - loop tl + loop (get_constraints ttp) | _ -> raise Not_found with Not_found -> if dce.debug then prerr_endline ("[DCE] Field " ^ n ^ " not found on " ^ (s_type_path c.cl_path)) else ()) diff --git a/src/optimization/inline.ml b/src/optimization/inline.ml index ab1ee4733da..d953b689a4f 100644 --- a/src/optimization/inline.ml +++ b/src/optimization/inline.ml @@ -234,7 +234,7 @@ let inline_default_config cf t = c.cl_params @ ct, pl @ cpl in let rec loop t = match follow t with - | TInst({cl_kind = KTypeParameter tl},_) -> List.fold_left (fun (params',tl') (params,tl) -> (params @ params',tl @ tl')) ([],[]) (List.map loop tl) + | TInst({cl_kind = KTypeParameter ttp},_) -> List.fold_left (fun (params',tl') (params,tl) -> (params @ params',tl @ tl')) ([],[]) (List.map loop (get_constraints ttp)) | TInst (c,pl) -> get_params c pl | _ -> ([],[]) in diff --git a/src/typing/fields.ml b/src/typing/fields.ml index 523d42e6f16..5ed4aba0f2e 100644 --- a/src/typing/fields.ml +++ b/src/typing/fields.ml @@ -319,11 +319,11 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) = snd (class_field_with_access e c tl) with Not_found -> try match c.cl_kind with - | KTypeParameter tl -> + | KTypeParameter ttp -> type_field_by_list (fun t -> match follow t with | TAbstract _ -> type_field_by_e type_field_by_type (mk_cast e t p); | _ -> raise Not_found - ) tl + ) (get_constraints ttp) | _ -> raise Not_found with Not_found -> type_field_by_interfaces e c diff --git a/src/typing/generic.ml b/src/typing/generic.ml index 131bec204b9..70bc96890d7 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -62,7 +62,7 @@ let make_generic ctx ps pt debug p = 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_typing_error ("Could not determine type for parameter " ^ ttp.ttp_name) p in - loop (name :: acc_name) ((follow ttp.ttp_type,t) :: acc_subst) ttpl tl + loop (name :: acc_name) ((ttp.ttp_type,t) :: acc_subst) ttpl tl | [],[] -> let name = String.concat "_" (List.rev acc_name) in name,acc_subst @@ -239,8 +239,9 @@ let build_generic_class ctx c p tl = | TInst (c2,tl) -> (match c2.cl_kind with | KTypeParameter tl -> - if not (TypeloadCheck.is_generic_parameter ctx c2) && has_ctor_constraint c2 then - raise_typing_error "Type parameters with a constructor cannot be used non-generically" p; + (* TPTODO *) + (* if not (TypeloadCheck.is_generic_parameter ctx c2) && has_ctor_constraint c2 then + raise_typing_error "Type parameters with a constructor cannot be used non-generically" p; *) recurse := true | _ -> ()); List.iter check_recursive tl; @@ -306,24 +307,20 @@ let build_generic_class ctx c p tl = add_dependency ctx.m.curmod mg; set_type_parameter_dependencies mg tl; let build_field cf_old = - (* We have to clone the type parameters (issue #4672). We cannot substitute the constraints immediately because - we need the full substitution list first. *) - let param_subst,params = List.fold_left (fun (subst,params) tp -> match follow tp.ttp_type with - | TInst(c,tl) as t -> - let t2 = TInst({c with cl_module = mg;},tl) in - (t,(t2,None)) :: subst,({tp with ttp_type=t2}) :: params - | _ -> die "" __LOC__ - ) ([],[]) cf_old.cf_params in + let params = List.map (fun ttp -> + let c = {ttp.ttp_class with cl_module = mg} in + let def = Option.map (generic_substitute_type gctx) ttp.ttp_default in + let constraints = match ttp.ttp_constraints with + | None -> None + | Some constraints -> Some (lazy (List.map (generic_substitute_type gctx) (Lazy.force constraints))) + in + let ttp' = mk_type_param c def constraints in + (ttp.ttp_type,ttp') + ) cf_old.cf_params in + let param_subst = List.map (fun (t,ttp) -> t,(ttp.ttp_type,None)) params in let gctx = {gctx with subst = param_subst @ gctx.subst} in let cf_new = {cf_old with cf_pos = cf_old.cf_pos; cf_expr_unoptimized = None} in (* copy *) - (* Type parameter constraints are substituted here. *) - cf_new.cf_params <- List.rev_map (fun tp -> match follow tp.ttp_type with - | TInst({cl_kind = KTypeParameter tl1} as c,_) -> - let tl1 = List.map (generic_substitute_type gctx) tl1 in - c.cl_kind <- KTypeParameter tl1; - tp (* TPTODO: weird mapping *) - | _ -> die "" __LOC__ - ) params; + cf_new.cf_params <- List.map (fun (_,ttp) -> ttp) params; let f () = ignore(follow cf_old.cf_type); (* We update here because the follow could resolve some TLazy things that end up modifying flags, such as diff --git a/src/typing/operators.ml b/src/typing/operators.ml index c297650c1a3..b9f0b7c927b 100644 --- a/src/typing/operators.ml +++ b/src/typing/operators.ml @@ -118,9 +118,9 @@ let rec classify t = | TAbstract ({ a_path = [],"Int" },[]) -> KInt | TAbstract ({ a_path = [],"Float" },[]) -> KFloat | TAbstract (a,[]) when List.exists (fun t -> match classify t with KInt | KFloat -> true | _ -> false) a.a_to -> KNumParam t - | TInst ({ cl_kind = KTypeParameter ctl },_) when List.exists (fun t -> match classify t with KInt | KFloat -> true | _ -> false) ctl -> KNumParam t + | TInst ({ cl_kind = KTypeParameter ttp },_) when List.exists (fun t -> match classify t with KInt | KFloat -> true | _ -> false) (get_constraints ttp) -> KNumParam t | TAbstract (a,[]) when List.exists (fun t -> match classify t with KString -> true | _ -> false) a.a_to -> KStrParam t - | TInst ({ cl_kind = KTypeParameter ctl },_) when List.exists (fun t -> match classify t with KString -> true | _ -> false) ctl -> KStrParam t + | TInst ({ cl_kind = KTypeParameter ttp },_) when List.exists (fun t -> match classify t with KString -> true | _ -> false) (get_constraints ttp) -> KStrParam t | TMono r when r.tm_type = None -> KUnk | TDynamic _ -> KDyn | _ -> KOther diff --git a/src/typing/typeload.ml b/src/typing/typeload.ml index e748a1d5271..66ee7d44d8a 100644 --- a/src/typing/typeload.ml +++ b/src/typing/typeload.ml @@ -286,28 +286,24 @@ let make_extension_type ctx tl = let ta = mk_anon ~fields (ref (Extend tl)) in ta -let check_param_constraints ctx t map c p = - match follow t with - | TMono _ -> () - | _ -> - let ctl = (match c.cl_kind with KTypeParameter l -> l | _ -> []) in - List.iter (fun ti -> - let ti = map ti in - try - unify_raise t ti p - with Error ({ err_message = Unify l } as err) -> - let fail() = - if not ctx.untyped then display_error_ext ctx.com { err with err_message = (Unify (Constraint_failure (s_type_path c.cl_path) :: l)) } - in - match follow t with - | TInst({cl_kind = KExpr e},_) -> - let e = type_expr {ctx with locals = PMap.empty} e (WithType.with_type ti) in - begin try unify_raise e.etype ti p - with Error { err_message = Unify _ } -> fail() end - | _ -> - fail() +let check_param_constraints ctx t map ttp p = + List.iter (fun ti -> + let ti = map ti in + try + unify_raise t ti p + with Error ({ err_message = Unify l } as err) -> + let fail() = + if not ctx.untyped then display_error_ext ctx.com { err with err_message = (Unify (Constraint_failure (s_type_path ttp.ttp_class.cl_path) :: l)) } + in + match follow t with + | TInst({cl_kind = KExpr e},_) -> + let e = type_expr {ctx with locals = PMap.empty} e (WithType.with_type ti) in + begin try unify_raise e.etype ti p + with Error { err_message = Unify _ } -> fail() end + | _ -> + fail() - ) ctl + ) (get_constraints ttp) type load_instance_param_mode = | ParamNormal @@ -357,7 +353,8 @@ let rec load_params ctx info params p = in let checks = DynArray.create () in let rec loop tl1 tl2 is_rest = match tl1,tl2 with - | t :: tl1,({ttp_name=name;ttp_type=t2}) :: tl2 -> + | t :: tl1,ttp:: tl2 -> + let name = ttp.ttp_name in let t,pt = load_param t in let check_const c = let is_expression = (match t with TInst ({ cl_kind = KExpr _ },_) -> true | _ -> false) in @@ -370,15 +367,14 @@ let rec load_params ctx info params p = raise_typing_error "Type parameter is expected to be a constant value" p in let is_rest = is_rest || name = "Rest" && info.build_kind = BuildGenericBuild in - let t = match follow t2 with - | TInst ({ cl_kind = KTypeParameter [] } as c, []) when (match info.build_kind with BuildGeneric _ -> false | _ -> true) -> - check_const c; + let t = match ttp.ttp_constraints with + | None when (match info.build_kind with BuildGeneric _ -> false | _ -> true) -> + check_const ttp.ttp_class; t - | TInst (c,[]) -> - check_const c; - DynArray.add checks (t,c,pt); + | _ -> + check_const ttp.ttp_class; + DynArray.add checks (t,ttp,pt); t - | _ -> die "" __LOC__ in t :: loop tl1 tl2 is_rest | [],[] -> @@ -753,7 +749,6 @@ let rec type_type_param ctx host path get_params p tp = let n = fst tp.tp_name in let c = mk_class ctx.m.curmod (fst path @ [snd path],n) (pos tp.tp_name) (pos tp.tp_name) in c.cl_params <- type_type_params ctx host c.cl_path get_params p tp.tp_params; - c.cl_kind <- KTypeParameter []; c.cl_meta <- tp.Ast.tp_meta; if host = TPHEnumConstructor then c.cl_meta <- (Meta.EnumConstructorParam,[],null_pos) :: c.cl_meta; let t = TInst (c,extract_param_types c.cl_params) in @@ -777,32 +772,36 @@ let rec type_type_param ctx host path get_params p tp = ) "default" in Some (TLazy r) in - match tp.tp_constraints with - | None -> - mk_type_param n t default - | Some th -> - let r = make_lazy ctx t (fun r -> - let ctx = { ctx with type_params = ctx.type_params @ get_params() } in - let rec loop th = match fst th with - | CTIntersection tl -> List.map (load_complex_type ctx true) tl - | CTParent ct -> loop ct - | _ -> [load_complex_type ctx true th] - in - let constr = loop th in - (* check against direct recursion *) - let rec loop t = - match follow t with - | TInst (c2,_) when c == c2 -> raise_typing_error "Recursive constraint parameter is not allowed" p - | TInst ({ cl_kind = KTypeParameter cl },_) -> - List.iter loop cl - | _ -> - () - in - List.iter loop constr; - c.cl_kind <- KTypeParameter constr; - t - ) "constraint" in - mk_type_param n (TLazy r) default + let ttp = match tp.tp_constraints with + | None -> + mk_type_param c default None + | Some th -> + let constraints = lazy ( + let ctx = { ctx with type_params = ctx.type_params @ get_params() } in + let rec loop th = match fst th with + | CTIntersection tl -> List.map (load_complex_type ctx true) tl + | CTParent ct -> loop ct + | _ -> [load_complex_type ctx true th] + in + let constr = loop th in + (* check against direct recursion *) + let rec loop t = + match follow t with + | TInst (c2,_) when c == c2 -> + raise_typing_error "Recursive constraint parameter is not allowed" p + | TInst ({ cl_kind = KTypeParameter ttp },_) -> + List.iter loop (get_constraints ttp) + | _ -> + () + in + List.iter loop constr; + constr + ) in + delay ctx PConnectField (fun () -> ignore (Lazy.force constraints)); + mk_type_param c default (Some constraints) + in + c.cl_kind <- KTypeParameter ttp; + ttp and type_type_params ctx host path get_params p tpl = let names = ref [] in @@ -845,21 +844,16 @@ let load_core_class ctx c = let init_core_api ctx c = let ccore = load_core_class ctx c in begin try - List.iter2 (fun tp1 tp2 -> match follow tp1.ttp_type, follow tp2.ttp_type with - | TInst({cl_kind = KTypeParameter l1},_),TInst({cl_kind = KTypeParameter l2},_) -> - begin try - List.iter2 (fun t1 t2 -> type_eq EqCoreType t2 t1) l1 l2 - with - | Invalid_argument _ -> - raise_typing_error "Type parameters must have the same number of constraints as core type" c.cl_pos - | Unify_error l -> - (* TODO send as one call with sub errors *) - display_error ctx.com ("Type parameter " ^ tp2.ttp_name ^ " has different constraint than in core type") c.cl_pos; - display_error ctx.com (error_msg (Unify l)) c.cl_pos; - end - | t1,t2 -> - Printf.printf "%s %s" (s_type (print_context()) t1) (s_type (print_context()) t2); - die "" __LOC__ + List.iter2 (fun ttp1 ttp2 -> + try + List.iter2 (fun t1 t2 -> type_eq EqCoreType t2 t1) (get_constraints ttp1) (get_constraints ttp2) + with + | Invalid_argument _ -> + raise_typing_error "Type parameters must have the same number of constraints as core type" c.cl_pos + | Unify_error l -> + (* TODO send as one call with sub errors *) + display_error ctx.com ("Type parameter " ^ ttp2.ttp_name ^ " has different constraint than in core type") c.cl_pos; + display_error ctx.com (error_msg (Unify l)) c.cl_pos; ) ccore.cl_params c.cl_params; with Invalid_argument _ -> raise_typing_error "Class must have the same number of type parameters as core type" c.cl_pos diff --git a/src/typing/typeloadCheck.ml b/src/typing/typeloadCheck.ml index b9030afd9c5..a144dcace14 100644 --- a/src/typing/typeloadCheck.ml +++ b/src/typing/typeloadCheck.ml @@ -62,28 +62,27 @@ let valid_redefinition ctx map1 map2 f1 t1 f2 t2 = (* child, parent *) | l1, l2 when List.length l1 = List.length l2 -> let to_check = ref [] in (* TPTODO: defaults *) - let monos = List.map2 (fun tp1 tp2 -> - (match follow tp1.ttp_type, follow tp2.ttp_type with - | TInst ({ cl_kind = KTypeParameter ct1 } as c1,pl1), TInst ({ cl_kind = KTypeParameter ct2 } as c2,pl2) -> - (match ct1, ct2 with - | [], [] -> () - | _, _ when List.length ct1 = List.length ct2 -> - (* if same constraints, they are the same type *) - let check monos = - List.iter2 (fun t1 t2 -> - try - let t1 = apply_params l1 monos (apply_params c1.cl_params pl1 (map2 t1)) in - let t2 = apply_params l2 monos (apply_params c2.cl_params pl2 (map1 t2)) in - type_eq EqStrict t1 t2 - with Unify_error l -> - raise (Unify_error (Unify_custom "Constraints differ" :: l)) - ) ct1 ct2 - in - to_check := check :: !to_check; - | _ -> - raise (Unify_error [Unify_custom "Different number of constraints"])) - | _ -> ()); - TInst (mk_class null_module ([],tp1.ttp_name) null_pos null_pos,[]) + let monos = List.map2 (fun ttp1 ttp2 -> + let ct1 = get_constraints ttp1 in + let ct2 = get_constraints ttp2 in + (match ct1, ct2 with + | [], [] -> () + | _, _ when List.length ct1 = List.length ct2 -> + (* if same constraints, they are the same type *) + let check monos = + List.iter2 (fun t1 t2 -> + try + let t1 = apply_params l1 monos (map2 t1) in + let t2 = apply_params l2 monos (map1 t2) in + type_eq EqStrict t1 t2 + with Unify_error l -> + raise (Unify_error (Unify_custom "Constraints differ" :: l)) + ) ct1 ct2 + in + to_check := check :: !to_check; + | _ -> + raise (Unify_error [Unify_custom "Different number of constraints"])); + TInst (mk_class null_module ([],ttp1.ttp_name) null_pos null_pos,[]) ) l1 l2 in List.iter (fun f -> f monos) !to_check; apply_params l1 monos t1, apply_params l2 monos t2 diff --git a/src/typing/typer.ml b/src/typing/typer.ml index 3b2a53ffad8..f8f69f69da9 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -1046,9 +1046,9 @@ and type_new ctx ptp el with_type force_inline p = unify_constructor_call c fa in try begin match Abstract.follow_with_forward_ctor t with - | TInst ({cl_kind = KTypeParameter tl} as c,params) -> + | TInst ({cl_kind = KTypeParameter ttp} as c,params) -> if not (TypeloadCheck.is_generic_parameter ctx c) then raise_typing_error "Only generic type parameters can be constructed" p; - begin match get_constructible_constraint ctx tl p with + begin match get_constructible_constraint ctx (get_constraints ttp) p with | None -> raise_typing_error_ext (make_error (No_constructor (TClassDecl c)) p) | Some(tl,tr) -> diff --git a/src/typing/typerBase.ml b/src/typing/typerBase.ml index 3dea5bf637a..b03fce5ebe2 100644 --- a/src/typing/typerBase.ml +++ b/src/typing/typerBase.ml @@ -309,8 +309,8 @@ let get_constructible_constraint ctx tl p = end; | TAbstract({a_path = ["haxe"],"Constructible"},[t1]) -> Some (extract_function t1) - | TInst({cl_kind = KTypeParameter tl1},_) -> - begin match loop tl1 with + | TInst({cl_kind = KTypeParameter ttp},_) -> + begin match loop (get_constraints ttp) with | None -> loop tl | Some _ as t -> t end diff --git a/src/typing/typerDisplay.ml b/src/typing/typerDisplay.ml index b0070783990..d22316512af 100644 --- a/src/typing/typerDisplay.ml +++ b/src/typing/typerDisplay.ml @@ -251,14 +251,14 @@ let rec handle_signature_display ctx e_ast with_type = l in let find_constructor_types t = match follow t with - | TInst ({cl_kind = KTypeParameter tl} as c,_) -> + | TInst ({cl_kind = KTypeParameter ttp} as c,_) -> let rec loop tl = match tl with | [] -> raise_typing_error_ext (make_error (No_constructor (TClassDecl c)) p) | t :: tl -> match follow t with | TAbstract({a_path = ["haxe"],"Constructible"},[t]) -> t | _ -> loop tl in - [loop tl,None,PMap.empty] + [loop (get_constraints ttp),None,PMap.empty] | TInst (c,tl) | TAbstract({a_impl = Some c},tl) -> Display.merge_core_doc ctx (TClassDecl c); let fa = get_constructor_access c tl p in @@ -628,7 +628,7 @@ let handle_display ctx e_ast dk mode with_type = false end end - | ITTypeParameter {cl_kind = KTypeParameter tl} when get_constructible_constraint ctx tl null_pos <> None -> + | ITTypeParameter {cl_kind = KTypeParameter ttp} when get_constructible_constraint ctx (get_constraints ttp) null_pos <> None -> true | _ -> false ) r.fitems in From 048fca21744bc441efc368c7cf29cc62ad446ba2 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 20 Dec 2023 08:30:27 +0100 Subject: [PATCH 034/184] [messageReporting] Add config to use absolute positions (#11439) * [messageReporting] add -D message.absolute-positions * [tests] add test for -D message.absolute-positions --- src-json/define.json | 5 ++ src/compiler/messageReporting.ml | 49 ++++++++++++------- src/macro/eval/evalLuv.ml | 3 +- tests/misc/projects/Issue11439/Main.hx | 5 ++ .../projects/Issue11439/compile-fail.hxml | 2 + .../Issue11439/compile-fail.hxml.stderr | 1 + .../projects/Issue11439/compile2-fail.hxml | 3 ++ .../Issue11439/compile2-fail.hxml.stderr | 1 + .../projects/Issue11439/compile3-fail.hxml | 4 ++ .../Issue11439/compile3-fail.hxml.stderr | 6 +++ 10 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 tests/misc/projects/Issue11439/Main.hx create mode 100644 tests/misc/projects/Issue11439/compile-fail.hxml create mode 100644 tests/misc/projects/Issue11439/compile-fail.hxml.stderr create mode 100644 tests/misc/projects/Issue11439/compile2-fail.hxml create mode 100644 tests/misc/projects/Issue11439/compile2-fail.hxml.stderr create mode 100644 tests/misc/projects/Issue11439/compile3-fail.hxml create mode 100644 tests/misc/projects/Issue11439/compile3-fail.hxml.stderr diff --git a/src-json/define.json b/src-json/define.json index a898ca75e68..e95cc7ff095 100644 --- a/src-json/define.json +++ b/src-json/define.json @@ -790,6 +790,11 @@ "define": "message.no-color", "doc": "Disable ANSI color codes in message reporting." }, + { + "name": "MessageAbsolutePositions", + "define": "message.absolute-positions", + "doc": "Use absolute character positions instead of line/columns for message reporting." + }, { "name": "MessageLogFile", "define": "message.log-file", diff --git a/src/compiler/messageReporting.ml b/src/compiler/messageReporting.ml index 4094ae5cb7c..8bd6e986367 100644 --- a/src/compiler/messageReporting.ml +++ b/src/compiler/messageReporting.ml @@ -65,13 +65,15 @@ let resolve_file ctx f = let error_printer file line = Printf.sprintf "%s:%d:" file line type error_context = { + absolute_positions : bool; mutable last_positions : pos IntMap.t; mutable max_lines : int IntMap.t; mutable gutter : int IntMap.t; mutable previous : (pos * MessageSeverity.t * int) option; } -let create_error_context () = { +let create_error_context absolute_positions = { + absolute_positions = absolute_positions; last_positions = IntMap.empty; max_lines = IntMap.empty; gutter = IntMap.empty; @@ -97,7 +99,10 @@ let compiler_pretty_message_string com ectx cm = let f = Common.find_file com f in let l1, p1, l2, p2 = Lexer.get_pos_coords cm.cm_pos in let lines = resolve_source f l1 p1 l2 p2 in - let epos = Lexer.get_error_pos error_printer cm.cm_pos in + let epos = + if ectx.absolute_positions then TPrinting.Printer.s_pos cm.cm_pos + else Lexer.get_error_pos error_printer cm.cm_pos + in (l1, p1, l2, p2, epos, lines) end with Not_found | Sys_error _ -> (1, 1, 1, 1, cm.cm_pos.pfile, []) @@ -243,7 +248,7 @@ let compiler_pretty_message_string com ectx cm = ) end -let compiler_message_string cm = +let compiler_message_string ectx cm = let str = match cm.cm_severity with | MessageSeverity.Warning -> "Warning : " ^ cm.cm_message | Information | Error | Hint -> cm.cm_message @@ -252,7 +257,10 @@ let compiler_message_string cm = if cm.cm_pos = null_pos then Some str else begin - let epos = Lexer.get_error_pos error_printer cm.cm_pos in + let epos = + if ectx.absolute_positions then TPrinting.Printer.s_pos cm.cm_pos + else Lexer.get_error_pos error_printer cm.cm_pos + in let str = let lines = match (ExtString.String.nsplit str "\n") with @@ -264,7 +272,7 @@ let compiler_message_string cm = Some (Printf.sprintf "%s : %s" epos str) end -let compiler_indented_message_string cm = +let compiler_indented_message_string ectx cm = match cm.cm_message with (* Filter some messages that don't add much when using this message renderer *) | "End of overload failure reasons" -> None @@ -278,7 +286,10 @@ let compiler_indented_message_string cm = if cm.cm_pos = null_pos then Some str else begin - let epos = Lexer.get_error_pos error_printer cm.cm_pos in + let epos = + if ectx.absolute_positions then TPrinting.Printer.s_pos cm.cm_pos + else Lexer.get_error_pos error_printer cm.cm_pos + in let lines = match (ExtString.String.nsplit str "\n") with | first :: rest -> (cm.cm_depth, first) :: List.map (fun msg -> (cm.cm_depth+1, msg)) rest @@ -299,10 +310,10 @@ let get_max_line max_lines messages = exception ConfigError of string -let get_formatter com ectx def default = +let get_formatter com def default = let format_mode = Define.defined_value_safe ~default com.defines def in match format_mode with - | "pretty" -> compiler_pretty_message_string com ectx + | "pretty" -> compiler_pretty_message_string com | "indent" -> compiler_indented_message_string | "classic" -> compiler_message_string | m -> begin @@ -318,11 +329,12 @@ let print_error (err : Error.error) = !ret let format_messages com messages = - let ectx = create_error_context () in + let absolute_positions = Define.defined com.defines Define.MessageAbsolutePositions in + let ectx = create_error_context absolute_positions in ectx.max_lines <- get_max_line ectx.max_lines messages; - let message_formatter = get_formatter com ectx Define.MessageReporting "classic" in + let message_formatter = get_formatter com Define.MessageReporting "classic" in let lines = List.rev ( - List.fold_left (fun lines cm -> match (message_formatter cm) with + List.fold_left (fun lines cm -> match (message_formatter ectx cm) with | None -> lines | Some str -> str :: lines ) [] messages @@ -330,18 +342,19 @@ let format_messages com messages = ExtLib.String.join "\n" lines let display_messages ctx on_message = begin - let ectx = create_error_context () in + let absolute_positions = Define.defined ctx.com.defines Define.MessageAbsolutePositions in + let ectx = create_error_context absolute_positions in ectx.max_lines <- get_max_line ectx.max_lines ctx.messages; - let get_formatter _ _ def default = - try get_formatter ctx.com ectx def default + let get_formatter _ def default = + try get_formatter ctx.com def default with | ConfigError s -> error ctx s null_pos; compiler_message_string in - let message_formatter = get_formatter ctx.com ectx Define.MessageReporting "classic" in - let log_formatter = get_formatter ctx.com ectx Define.MessageLogFormat "indent" in + let message_formatter = get_formatter ctx.com Define.MessageReporting "classic" in + let log_formatter = get_formatter ctx.com Define.MessageLogFormat "indent" in let log_messages = ref (Define.defined ctx.com.defines Define.MessageLogFile) in let log_message = ref None in @@ -358,7 +371,7 @@ let display_messages ctx on_message = begin in log_message := (Some (fun msg -> - match (log_formatter msg) with + match (log_formatter ectx msg) with | None -> () | Some str -> Rbuffer.add_string buf (str ^ "\n"))); @@ -378,7 +391,7 @@ let display_messages ctx on_message = begin List.iter (fun cm -> if !log_messages then (Option.get !log_message) cm; - match (message_formatter cm) with + match (message_formatter ectx cm) with | None -> () | Some str -> on_message cm.cm_severity str ) (List.rev ctx.messages); diff --git a/src/macro/eval/evalLuv.ml b/src/macro/eval/evalLuv.ml index 800d58020b6..12099b5f6b9 100644 --- a/src/macro/eval/evalLuv.ml +++ b/src/macro/eval/evalLuv.ml @@ -554,7 +554,8 @@ let uv_error_fields = [ let messages = ref [] in HaxeError.recurse_error (fun depth err -> let cm = make_compiler_message ~from_macro:err.err_from_macro (HaxeError.error_msg err.err_message) err.err_pos depth DKCompilerMessage Error in - match MessageReporting.compiler_message_string cm with + let ectx = MessageReporting.create_error_context false in + match MessageReporting.compiler_message_string ectx cm with | None -> () | Some str -> messages := str :: !messages ) err; diff --git a/tests/misc/projects/Issue11439/Main.hx b/tests/misc/projects/Issue11439/Main.hx new file mode 100644 index 00000000000..f33318b918b --- /dev/null +++ b/tests/misc/projects/Issue11439/Main.hx @@ -0,0 +1,5 @@ +class Main { + static function main() { + var foo:Int = "whoops"; + } +} diff --git a/tests/misc/projects/Issue11439/compile-fail.hxml b/tests/misc/projects/Issue11439/compile-fail.hxml new file mode 100644 index 00000000000..d0162e592e8 --- /dev/null +++ b/tests/misc/projects/Issue11439/compile-fail.hxml @@ -0,0 +1,2 @@ +-main Main +-D message.absolute-positions diff --git a/tests/misc/projects/Issue11439/compile-fail.hxml.stderr b/tests/misc/projects/Issue11439/compile-fail.hxml.stderr new file mode 100644 index 00000000000..93a7f572059 --- /dev/null +++ b/tests/misc/projects/Issue11439/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx: 41-64 : String should be Int diff --git a/tests/misc/projects/Issue11439/compile2-fail.hxml b/tests/misc/projects/Issue11439/compile2-fail.hxml new file mode 100644 index 00000000000..7b3a30f767c --- /dev/null +++ b/tests/misc/projects/Issue11439/compile2-fail.hxml @@ -0,0 +1,3 @@ +-main Main +-D message.reporting=indent +-D message.absolute-positions diff --git a/tests/misc/projects/Issue11439/compile2-fail.hxml.stderr b/tests/misc/projects/Issue11439/compile2-fail.hxml.stderr new file mode 100644 index 00000000000..93a7f572059 --- /dev/null +++ b/tests/misc/projects/Issue11439/compile2-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx: 41-64 : String should be Int diff --git a/tests/misc/projects/Issue11439/compile3-fail.hxml b/tests/misc/projects/Issue11439/compile3-fail.hxml new file mode 100644 index 00000000000..930fd2b7043 --- /dev/null +++ b/tests/misc/projects/Issue11439/compile3-fail.hxml @@ -0,0 +1,4 @@ +-main Main +-D message.reporting=pretty +-D message.no-color +-D message.absolute-positions diff --git a/tests/misc/projects/Issue11439/compile3-fail.hxml.stderr b/tests/misc/projects/Issue11439/compile3-fail.hxml.stderr new file mode 100644 index 00000000000..30c05894b98 --- /dev/null +++ b/tests/misc/projects/Issue11439/compile3-fail.hxml.stderr @@ -0,0 +1,6 @@ +[ERROR] Main.hx: 41-64 + + 3 | var foo:Int = "whoops"; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | String should be Int + From 4a175dfdb42d994221c2bf1413a0a2a8c4386cc7 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Thu, 21 Dec 2023 18:11:11 +0000 Subject: [PATCH 035/184] [cpp] Enum Type Checking (#11444) * Give enums a unique class ID * Add more type check scaffolding * Add test * Use Int32.zero --- src/generators/gencpp.ml | 26 +++++++++++++++++++++--- tests/unit/src/unit/issues/Issue11442.hx | 22 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 tests/unit/src/unit/issues/Issue11442.hx diff --git a/src/generators/gencpp.ml b/src/generators/gencpp.ml index 2bc1a5b3913..264bb28276b 100644 --- a/src/generators/gencpp.ml +++ b/src/generators/gencpp.ml @@ -3442,7 +3442,7 @@ let cpp_class_hash interface = let rec is_constant_zero expr = match expr.cppexpr with | CppFloat x when (float_of_string x) = 0.0 -> true - | CppInt i when i = Int32.of_int 0 -> true + | CppInt i when i = Int32.zero -> true | CppCastScalar(expr,_) -> is_constant_zero(expr) | _ -> false ;; @@ -5238,6 +5238,9 @@ let generate_enum_files baseCtx enum_def super_deps meta = let ctx = file_context baseCtx cpp_file debug false in let strq = strq ctx.ctx_common in + let classId = try Hashtbl.find baseCtx.ctx_type_ids (class_text enum_def.e_path) with Not_found -> Int32.zero in + let classIdTxt = Printf.sprintf "0x%08lx" classId in + if (debug>1) then print_endline ("Found enum definition:" ^ (join_class_path class_path "::" )); @@ -5279,6 +5282,10 @@ let generate_enum_files baseCtx enum_def super_deps meta = output_cpp ("HX_DEFINE_CREATE_ENUM(" ^ class_name ^ ")\n\n"); + output_cpp ("bool " ^ class_name ^ "::_hx_isInstanceOf(int inClassId) {\n"); + output_cpp ("\treturn inClassId == (int)0x00000001 || inClassId == ::hx::EnumBase_obj::_hx_ClassId || inClassId == _hx_ClassId;\n"); + output_cpp ("}\n"); + output_cpp ("int " ^ class_name ^ "::__FindIndex(::String inName)\n{\n"); PMap.iter (fun _ constructor -> let name = constructor.ef_name in @@ -5390,13 +5397,15 @@ let generate_enum_files baseCtx enum_def super_deps meta = output_h ("{\n\ttypedef " ^ super ^ " super;\n"); output_h ("\t\ttypedef " ^ class_name ^ " OBJ_;\n"); output_h "\n\tpublic:\n"; + output_h ("\t\tenum { _hx_ClassId = " ^ classIdTxt ^ " };\n\n"); output_h ("\t\t" ^ class_name ^ "() {};\n"); output_h ("\t\tHX_DO_ENUM_RTTI;\n"); output_h ("\t\tstatic void __boot();\n"); output_h ("\t\tstatic void __register();\n"); output_h ("\t\tstatic bool __GetStatic(const ::String &inName, Dynamic &outValue, ::hx::PropertyAccess inCallProp);\n"); output_h ("\t\t::String GetEnumName( ) const { return " ^ (strq (join_class_path class_path ".")) ^ "; }\n" ); - output_h ("\t\t::String __ToString() const { return " ^ (strq (just_class_name ^ ".") )^ " + _hx_tag; }\n\n"); + output_h ("\t\t::String __ToString() const { return " ^ (strq (just_class_name ^ ".") )^ " + _hx_tag; }\n"); + output_h ("\t\tbool _hx_isInstanceOf(int inClassId);\n\n"); PMap.iter (fun _ constructor -> @@ -5761,7 +5770,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta then 0 else 1 in let scriptable = inScriptable && not class_def.cl_private in - let classId = try Hashtbl.find baseCtx.ctx_type_ids (class_text class_def.cl_path) with Not_found -> Int32.of_int 0 in + let classId = try Hashtbl.find baseCtx.ctx_type_ids (class_text class_def.cl_path) with Not_found -> Int32.zero in let classIdTxt = Printf.sprintf "0x%08lx" classId in (* Config *) @@ -8564,6 +8573,17 @@ let generate_source ctx = if (is_internal) then (if (debug>1) then print_endline (" internal enum " ^ name )) else begin + let rec makeId enum_name seed = + let id = gen_hash32 seed enum_name in + (* reserve first 100 ids for runtime *) + if id < Int32.of_int 100 || Hashtbl.mem existingIds id then + makeId enum_name (seed+100) + else begin + Hashtbl.add existingIds id true; + Hashtbl.add ctx.ctx_type_ids enum_name id; + end in + makeId name 0; + let meta = Texpr.build_metadata common_ctx.basic object_def in if (enum_def.e_extern) then (if (debug>1) then print_endline ("external enum " ^ name )); diff --git a/tests/unit/src/unit/issues/Issue11442.hx b/tests/unit/src/unit/issues/Issue11442.hx new file mode 100644 index 00000000000..77921d7d869 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11442.hx @@ -0,0 +1,22 @@ +package unit.issues; + +import utest.Assert; + +enum Dummy { + DummyCtor; +} + +class Issue11442 extends Test { + function test() { + f(Std.isOfType(DummyCtor, haxe.ds.Option)); + t(Std.isOfType(DummyCtor, Dummy)); + + try { + throw DummyCtor; + } catch(e:haxe.ds.Option) { + Assert.fail("wrong catch"); + } catch(e:Dummy) { + Assert.pass("correct catch"); + } + } +} \ No newline at end of file From 2b22ff950f8092a9efe370ebf1fd1b37c7323c1a Mon Sep 17 00:00:00 2001 From: Zeta <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Thu, 21 Dec 2023 19:20:35 +0100 Subject: [PATCH 036/184] [display] Insert EDisplay in the proper position when parsing a call expression. (#11441) --- src/syntax/grammar.mly | 20 ++++++++++++++++++-- tests/display/src/cases/Signature.hx | 16 ++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/syntax/grammar.mly b/src/syntax/grammar.mly index 9ac02cebc88..cce1e22bfa3 100644 --- a/src/syntax/grammar.mly +++ b/src/syntax/grammar.mly @@ -1715,8 +1715,24 @@ and parse_call_params f p1 s = let e = check_signature_mark e p1 p2 in f (List.rev (e :: acc)) p2 | [< '(Comma,p2); '(PClose,p3) >] -> - let e = check_signature_mark e p1 p3 in - f (List.rev (e :: acc)) p3 + if (is_signature_display()) then begin + let prev_arg_pos = punion p1 p2 in + let comma_paren_pos = punion p2 p3 in + (* first check wether the display position is within the previous argument *) + if encloses_position_gt display_position#get prev_arg_pos then begin + (* wrap the argument that was just parsed *) + let e = mk_display_expr e DKMarked in + f (List.rev (e :: acc)) p3 + (* then check wether the display position is between the comma and the closing parenthesis *) + end else if encloses_position_gt display_position#get comma_paren_pos then begin + (* add a dummy final argument *) + let e2 = mk_display_expr (mk_null_expr comma_paren_pos) DKMarked in + f (List.rev (e2 :: e :: acc)) p3 + end else f (List.rev (e :: acc)) p3 + end else begin + (* if not in signature display mode don't check anything *) + f (List.rev (e :: acc)) p3 + end | [< '(Comma,p2) >] -> let e = check_signature_mark e p1 p2 in parse_next_param (e :: acc) p2 diff --git a/tests/display/src/cases/Signature.hx b/tests/display/src/cases/Signature.hx index d8914e51642..ef10b6f770a 100644 --- a/tests/display/src/cases/Signature.hx +++ b/tests/display/src/cases/Signature.hx @@ -282,4 +282,20 @@ class Signature extends DisplayTestCase { function testStaticVisibility() { sigEq(0, [["s:String"]], signature(pos(1))); } + + /** + class Foo { + public static function foo(a:Int, b:Int) {} + } + + class Main { + static function main() { + Foo.foo(1{-1-},{-2-}); + } + } + **/ + function testTrailingCommaEdgeCase() { + sigEq(0, [["a:Int","b:Int"]], signature(pos(1))); + sigEq(1, [["a:Int","b:Int"]], signature(pos(2))); + } } From ed838d789588487e817a326b60d31c4397ce9012 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Sun, 24 Dec 2023 09:52:49 +0100 Subject: [PATCH 037/184] [matcher] follow when looking for GADT return types closes #11446 --- src/generators/genjvm.ml | 6 +++++- src/typing/matcher/exprToPattern.ml | 6 +++++- tests/unit/src/unit/issues/Issue11446.hx | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 tests/unit/src/unit/issues/Issue11446.hx diff --git a/src/generators/genjvm.ml b/src/generators/genjvm.ml index 7efa5cd4968..1fa8a737d7e 100644 --- a/src/generators/genjvm.ml +++ b/src/generators/genjvm.ml @@ -2116,7 +2116,11 @@ class texpr_to_jvm | TEnumParameter(e1,ef,i) -> self#texpr rvalue_any e1; let path,name,jsig_arg = match follow ef.ef_type with - | TFun(tl,TEnum(en,_)) -> + | TFun(tl,tr) -> + let en = match follow tr with + | TEnum(en,_) -> en + | _ -> die "" __LOC__ + in let n,_,t = List.nth tl i in en.e_path,n,self#vtype t | _ -> die "" __LOC__ diff --git a/src/typing/matcher/exprToPattern.ml b/src/typing/matcher/exprToPattern.ml index 0f787760903..3cb8edf06f4 100644 --- a/src/typing/matcher/exprToPattern.ml +++ b/src/typing/matcher/exprToPattern.ml @@ -252,7 +252,11 @@ let rec make pctx toplevel t e = | ECall(e1,el) -> let e1 = type_expr ctx e1 (WithType.with_type t) in begin match e1.eexpr,follow e1.etype with - | TField(_, FEnum(en,ef)),TFun(_,TEnum(_,tl)) -> + | TField(_, FEnum(en,ef)),TFun(_,tr) -> + let tl = match follow tr with + | TEnum(_,tl) -> tl + | _ -> fail() + in let map = apply_params en.e_params tl in let monos = Monomorph.spawn_constrained_monos map ef.ef_params in let map t = map (apply_params ef.ef_params monos t) in diff --git a/tests/unit/src/unit/issues/Issue11446.hx b/tests/unit/src/unit/issues/Issue11446.hx new file mode 100644 index 00000000000..fd24f4b1a5b --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11446.hx @@ -0,0 +1,19 @@ +package unit.issues; + +typedef Td = E; + +private enum E { + C(s:String):Td; +} + +private function match(e:E) { + return switch (e) { + case C(s): s; + } +} + +class Issue11446 extends Test { + function test() { + eq("foo", match(C("foo"))); + } +} From 5ddfcc84f7ee27c9df14f82f27d01ddf51e92df7 Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sun, 24 Dec 2023 10:36:48 +0100 Subject: [PATCH 038/184] [hl] added OAsm --- src/generators/genhl.ml | 22 ++++++++++++++++++++++ src/generators/hl2c.ml | 2 ++ src/generators/hlcode.ml | 13 +++++++++++++ src/generators/hlinterp.ml | 4 ++++ src/generators/hlopt.ml | 11 +++++++++++ 5 files changed, 52 insertions(+) diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index 16b04edb53d..8ed3abbc49b 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -2086,6 +2086,28 @@ and eval_expr ctx e = let r = alloc_tmp ctx (to_type ctx e.etype) in op ctx (OUnsafeCast (r, eval_expr ctx value)); r + | "$asm", [mode; value] -> + let mode = (match get_const mode with + | TInt m -> Int32.to_int m + | _ -> abort "Constant mode required" e.epos + ) in + let value = (match get_const value with + | TInt m -> Int32.to_int m + | _ -> abort "Constant value required" e.epos + ) in + op ctx (OAsm (mode, value, 0)); + alloc_tmp ctx HVoid + | "$asm", [mode; value; reg] -> + let mode = (match get_const mode with + | TInt m -> Int32.to_int m + | _ -> abort "Constant mode required" e.epos + ) in + let value = (match get_const value with + | TInt m -> Int32.to_int m + | _ -> abort "Constant value required" e.epos + ) in + op ctx (OAsm (mode, value, (eval_expr ctx reg) + 1)); + alloc_tmp ctx HVoid | _ -> abort ("Unknown native call " ^ s) e.epos) | TEnumIndex v -> diff --git a/src/generators/hl2c.ml b/src/generators/hl2c.ml index 1e62c48e602..035b9838be5 100644 --- a/src/generators/hl2c.ml +++ b/src/generators/hl2c.ml @@ -1110,6 +1110,8 @@ let generate_function ctx f = Globals.die "" __LOC__ )) in sexpr "__hl_prefetch_m%d(%s)" mode expr + | OAsm _ -> + sexpr "UNSUPPORTED ASM OPCODE"; ) f.code; flush_options (Array.length f.code); unblock(); diff --git a/src/generators/hlcode.ml b/src/generators/hlcode.ml index d40313f9c26..1636c2546db 100644 --- a/src/generators/hlcode.ml +++ b/src/generators/hlcode.ml @@ -202,6 +202,7 @@ type opcode = | ORefOffset of reg * reg * reg | ONop of string | OPrefetch of reg * field index * int + | OAsm of int * int * reg type fundecl = { fpath : string * string; @@ -574,6 +575,18 @@ let ostr fstr o = | 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 + | OAsm (mode, value, reg) -> + match mode with + | 0 when reg = 0 -> + Printf.sprintf "asm %.2X" value + | 1 when reg = 0 -> + Printf.sprintf "asm scratch R%d" value + | 2 -> + Printf.sprintf "asm R%d := %d" value (reg - 1) + | 3 -> + Printf.sprintf "asm %d := R%d" (reg - 1) value + | _ -> + Printf.sprintf "asm[%d] %d%s" mode value (if reg = 0 then "" else ", " ^ string_of_int (reg-1)) let fundecl_name f = if snd f.fpath = "" then "fun$" ^ (string_of_int f.findex) else (fst f.fpath) ^ "." ^ (snd f.fpath) diff --git a/src/generators/hlinterp.ml b/src/generators/hlinterp.ml index 8979dcb1c01..c60b06cf30c 100644 --- a/src/generators/hlinterp.ml +++ b/src/generators/hlinterp.ml @@ -1154,6 +1154,8 @@ 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__) + | OAsm _ -> + throw_msg ctx "Unsupported ASM" | ONop _ | OPrefetch _ -> () ); @@ -2545,6 +2547,8 @@ let check code macros = (); | OPrefetch (r,f,_) -> if f = 0 then ignore(rtype r) else ignore(tfield r (f - 1) false) + | OAsm (_,_,r) -> + if r > 0 then ignore(rtype (r - 1)) ) 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 c11db0161aa..5081c31c9f5 100644 --- a/src/generators/hlopt.ml +++ b/src/generators/hlopt.ml @@ -166,6 +166,12 @@ let opcode_fx frw op = () | OPrefetch (r,_,_) -> read r + | OAsm (_,_,r) -> + if r > 0 then begin + (* assume both *) + read (r - 1); + write (r - 1); + end let opcode_eq a b = match a, b with @@ -437,6 +443,11 @@ let opcode_map read write op = | OPrefetch (r, fid, mode) -> let r2 = read r in OPrefetch (r2, fid, mode) + | OAsm (_, _, 0) -> + op + | OAsm (mode, value, r) -> + let r2 = read (r - 1) in + OAsm (mode, value, (write r2) + 1) (* build code graph *) From 8ab63f13ac09c2b4288437d3c6cdbcf563b1bac9 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Sun, 24 Dec 2023 14:27:24 +0100 Subject: [PATCH 039/184] [dump] fix module lookup closes #11447 --- src/codegen/codegen.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/codegen.ml b/src/codegen/codegen.ml index 5893255443e..b9ff78439eb 100644 --- a/src/codegen/codegen.ml +++ b/src/codegen/codegen.ml @@ -393,7 +393,7 @@ module Dump = struct List.iter (fun m -> print "%s:\n" (Path.UniqueKey.lazy_path m.m_extra.m_file); PMap.iter (fun _ (sign,mpath) -> - let m2 = (com.cs#get_context sign)#find_module mpath in + let m2 = com.module_lut#find 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 From bc660af559b3d77ebd7274904c98b0e23ebcd7eb Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sun, 24 Dec 2023 19:39:11 +0100 Subject: [PATCH 040/184] [hl] make sure -dce full will not remove @:struct fields as they match native code --- src/optimization/dce.ml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/optimization/dce.ml b/src/optimization/dce.ml index b4a1a7b4944..96c198cd7e0 100644 --- a/src/optimization/dce.ml +++ b/src/optimization/dce.ml @@ -622,7 +622,7 @@ and expr dce e = check_op dce op; check_and_add_feature dce "dynamic_array_write"; expr dce e1; - expr dce e2; + expr dce e2; | TArray(({etype = t} as e1),e2) when is_array t -> check_and_add_feature dce "array_read"; expr dce e1; @@ -733,8 +733,9 @@ let collect_entry_points dce com = match t with | TClassDecl c -> let keep_class = keep_whole_class dce c && (not (has_class_flag c CExtern) || (has_class_flag c CInterface)) in + let is_struct = dce.com.platform = Hl && Meta.has Meta.Struct c.cl_meta in let loop kind cf = - if keep_class || keep_field dce cf c kind then mark_field dce c cf kind + if keep_class || is_struct || keep_field dce cf c kind then mark_field dce c cf kind in List.iter (loop CfrStatic) c.cl_ordered_statics; List.iter (loop CfrMember) c.cl_ordered_fields; From 599e0ca4bf977f3cbb6936694b2bda674cd3fae1 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 27 Dec 2023 16:09:57 +0100 Subject: [PATCH 041/184] Internal dependency cleanup 2023 (#11451) * factor out field call candidate * load Std when creating typer instead of randomly when we need it * slightly split up exceptions.ml * lose genjs dependency on typeloadCheck * factor out expr preprocessing to lose a dependency between EvalDebugSocket and typecore * split up filters.ml a bit to lose macroContext -> filters because it brings a lot of other stuff * separate Typer.create from the rest to lose the macroContext dependency * lose some weird dependencies from string formatting * make Eval an isolated dependency * bring back catch that breaks tink --- src/codegen/codegen.ml | 1 + src/codegen/overloads.ml | 2 +- src/compiler/compiler.ml | 8 +- src/compiler/displayOutput.ml | 2 +- src/compiler/serverCompilationContext.ml | 8 +- src/context/common.ml | 101 +--------- src/context/display/display.ml | 231 +---------------------- src/context/display/displayEmitter.ml | 2 +- src/context/display/exprPreprocessing.ml | 224 ++++++++++++++++++++++ src/context/formatString.ml | 98 ++++++++++ src/context/memory.ml | 4 +- src/context/typecore.ml | 42 +---- src/core/naming.ml | 88 +++++++++ src/core/socket.ml | 13 +- src/filters/addFieldInits.ml | 68 +++++++ src/filters/exceptionFunctions.ml | 22 +++ src/filters/exceptions.ml | 27 +-- src/filters/filters.ml | 212 +-------------------- src/filters/filtersCommon.ml | 15 ++ src/filters/localStatic.ml | 63 +++++++ src/filters/renameVars.ml | 6 +- src/generators/genjs.ml | 4 +- src/generators/genjvm.ml | 4 +- src/generators/genswf9.ml | 4 +- src/macro/eval/eval.ml | 5 + src/macro/eval/evalContext.ml | 5 - src/macro/eval/evalDebugSocket.ml | 2 +- src/macro/eval/evalExceptions.ml | 1 - src/macro/eval/evalMain.ml | 3 +- src/macro/eval/evalStdLib.ml | 2 +- src/macro/eval/evalThread.ml | 2 +- src/macro/eval/evalTypes.ml | 1 + src/optimization/inline.ml | 4 +- src/typing/callUnification.ml | 1 + src/typing/fieldCallCandidate.ml | 39 ++++ src/typing/functionArguments.ml | 2 +- src/typing/generic.ml | 1 + src/typing/macroContext.ml | 24 +-- src/typing/overloadResolution.ml | 2 +- src/typing/typeload.ml | 11 -- src/typing/typeloadCheck.ml | 22 +-- src/typing/typeloadFields.ml | 2 +- src/typing/typeloadFunction.ml | 2 +- src/typing/typeloadModule.ml | 6 +- src/typing/typer.ml | 161 +--------------- src/typing/typerEntry.ml | 154 +++++++++++++++ 46 files changed, 865 insertions(+), 836 deletions(-) create mode 100644 src/context/display/exprPreprocessing.ml create mode 100644 src/context/formatString.ml create mode 100644 src/core/naming.ml create mode 100644 src/filters/addFieldInits.ml create mode 100644 src/filters/exceptionFunctions.ml create mode 100644 src/filters/localStatic.ml create mode 100644 src/macro/eval/eval.ml create mode 100644 src/macro/eval/evalTypes.ml create mode 100644 src/typing/fieldCallCandidate.ml create mode 100644 src/typing/typerEntry.ml diff --git a/src/codegen/codegen.ml b/src/codegen/codegen.ml index b9ff78439eb..0fb322c9f88 100644 --- a/src/codegen/codegen.ml +++ b/src/codegen/codegen.ml @@ -520,3 +520,4 @@ module ExtClass = struct let e_assign = mk (TBinop(OpAssign,ef1,e)) e.etype p in add_cl_init c e_assign end + \ No newline at end of file diff --git a/src/codegen/overloads.ml b/src/codegen/overloads.ml index 3657e537f31..5d326efdbe9 100644 --- a/src/codegen/overloads.ml +++ b/src/codegen/overloads.ml @@ -1,6 +1,6 @@ open Globals open Type -open Typecore +open FieldCallCandidate let same_overload_args ?(get_vmtype) t1 t2 f1 f2 = let f_transform = match get_vmtype with diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index ceb60f839a0..26860dfe498 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -178,7 +178,7 @@ module Setup = struct let fl = List.map (fun (file,extern) -> NativeLibraryHandler.add_native_lib com file extern) (List.rev native_libs) in (* Native lib pass 2: Initialize *) List.iter (fun f -> f()) fl; - Typer.create com macros + TyperEntry.create com macros let executable_path() = Extc.executable_path() @@ -424,7 +424,7 @@ with error ctx ("Error: No completion point was found") null_pos | DisplayException.DisplayException dex -> DisplayOutput.handle_display_exception ctx dex - | Out_of_memory | EvalExceptions.Sys_exit _ | Hlinterp.Sys_exit _ | DisplayProcessingGlobals.Completion _ as exc -> + | Out_of_memory | EvalTypes.Sys_exit _ | Hlinterp.Sys_exit _ | DisplayProcessingGlobals.Completion _ as exc -> (* We don't want these to be caught by the catchall below *) raise exc | e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" with _ -> true) && not Helper.is_debug_run -> @@ -450,7 +450,7 @@ let catch_completion_and_exit ctx callbacks run = ServerMessage.completion str; ctx.comm.write_err str; 0 - | EvalExceptions.Sys_exit i | Hlinterp.Sys_exit i -> + | EvalTypes.Sys_exit i | Hlinterp.Sys_exit i -> if i <> 0 then ctx.has_error <- true; finalize ctx; i @@ -483,7 +483,7 @@ let compile_ctx callbacks ctx = catch_completion_and_exit ctx callbacks run let create_context comm cs compilation_step params = { - com = Common.create compilation_step cs version params; + com = Common.create compilation_step cs version params (DisplayTypes.DisplayMode.create !Parser.display_mode); messages = []; has_next = false; has_error = false; diff --git a/src/compiler/displayOutput.ml b/src/compiler/displayOutput.ml index c1ddb3bf4d0..99ba1280bbd 100644 --- a/src/compiler/displayOutput.ml +++ b/src/compiler/displayOutput.ml @@ -344,7 +344,7 @@ let handle_type_path_exception ctx p c is_import pos = | None -> DisplayPath.TypePathHandler.complete_type_path com p | Some (c,cur_package) -> - let ctx = Typer.create com None in + let ctx = TyperEntry.create com None in DisplayPath.TypePathHandler.complete_type_path_inner ctx p c cur_package is_import end with Error.Fatal_error err -> error_ext ctx err; diff --git a/src/compiler/serverCompilationContext.ml b/src/compiler/serverCompilationContext.ml index bec9724e4c3..0f65f22c154 100644 --- a/src/compiler/serverCompilationContext.ml +++ b/src/compiler/serverCompilationContext.ml @@ -70,5 +70,9 @@ let ensure_macro_setup sctx = end let cleanup () = match !MacroContext.macro_interp_cache with - | Some interp -> EvalContext.GlobalState.cleanup interp - | None -> () \ No newline at end of file + | Some interp -> + (* curapi holds a reference to the typing context which we don't want to persist. Let's unset it so the + context can be collected. *) + interp.curapi <- Obj.magic "" + | None -> + () \ No newline at end of file diff --git a/src/context/common.ml b/src/context/common.ml index 10c6e484f40..401e51e974f 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -798,7 +798,7 @@ let get_config com = let memory_marker = [|Unix.time()|] -let create compilation_step cs version args = +let create compilation_step cs version args display_mode = let m = Type.mk_mono() in let rec com = { compilation_step = compilation_step; @@ -819,7 +819,7 @@ let create compilation_step cs version args = }; sys_args = args; debug = false; - display = DisplayTypes.DisplayMode.create !Parser.display_mode; + display = display_mode; verbose = false; foptimize = true; features = Hashtbl.create 0; @@ -1326,100 +1326,3 @@ let get_entry_point com = let e = Option.get com.main in (* must be present at this point *) (snd path, c, e) ) com.main_class - -let format_string com s p process_expr = - let e = ref None in - let pmin = ref p.pmin in - let min = ref (p.pmin + 1) in - let add_expr (enext,p) len = - min := !min + len; - let enext = process_expr enext p in - match !e with - | None -> e := Some enext - | Some prev -> - e := Some (EBinop (OpAdd,prev,enext),punion (pos prev) p) - in - let add enext len = - let p = { p with pmin = !min; pmax = !min + len } in - add_expr (enext,p) len - in - let add_sub start pos = - let len = pos - start in - if len > 0 || !e = None then add (EConst (String (String.sub s start len,SDoubleQuotes))) len - in - let len = String.length s in - let rec parse start pos = - if pos = len then add_sub start pos else - let c = String.unsafe_get s pos in - let pos = pos + 1 in - if c = '\'' then begin - incr pmin; - incr min; - end; - if c <> '$' || pos = len then parse start pos else - match String.unsafe_get s pos with - | '$' -> - (* double $ *) - add_sub start pos; - parse (pos + 1) (pos + 1) - | '{' -> - parse_group start pos '{' '}' "brace" - | 'a'..'z' | 'A'..'Z' | '_' -> - add_sub start (pos - 1); - incr min; - let rec loop i = - if i = len then i else - let c = String.unsafe_get s i in - match c with - | 'a'..'z' | 'A'..'Z' | '0'..'9' | '_' -> loop (i+1) - | _ -> i - in - let iend = loop (pos + 1) in - let len = iend - pos in - add (EConst (Ident (String.sub s pos len))) len; - parse (pos + len) (pos + len) - | _ -> - (* keep as-it *) - parse start pos - and parse_group start pos gopen gclose gname = - add_sub start (pos - 1); - let rec loop groups i = - if i = len then - match groups with - | [] -> die "" __LOC__ - | g :: _ -> Error.raise_typing_error ("Unclosed " ^ gname) { p with pmin = !pmin + g + 1; pmax = !pmin + g + 2 } - else - let c = String.unsafe_get s i in - if c = gopen then - loop (i :: groups) (i + 1) - else if c = gclose then begin - let groups = List.tl groups in - if groups = [] then i else loop groups (i + 1) - end else - loop groups (i + 1) - in - let send = loop [pos] (pos + 1) in - let slen = send - pos - 1 in - let scode = String.sub s (pos + 1) slen in - min := !min + 2; - begin - let e = - let ep = { p with pmin = !pmin + pos + 2; pmax = !pmin + send + 1 } in - let error msg pos = - if Lexer.string_is_whitespace scode then Error.raise_typing_error "Expression cannot be empty" ep - else Error.raise_typing_error msg pos - in - match ParserEntry.parse_expr_string com.defines scode ep error true with - | ParseSuccess(data,_,_) -> data - | ParseError(_,(msg,p),_) -> error (Parser.error_msg msg) p - in - add_expr e slen - end; - min := !min + 1; - parse (send + 1) (send + 1) - in - parse 0 0; - match !e with - | None -> die "" __LOC__ - | Some e -> e - diff --git a/src/context/display/display.ml b/src/context/display/display.ml index b6e865564d0..075839bbe12 100644 --- a/src/context/display/display.ml +++ b/src/context/display/display.ml @@ -30,233 +30,10 @@ module ReferencePosition = struct let reset () = reference_position := ("",null_pos,SKOther) end -module ExprPreprocessing = struct - let find_before_pos dm e = - let display_pos = ref (DisplayPosition.display_position#get) in - let was_annotated = ref false in - let is_annotated,is_completion = match dm with - | DMDefault -> (fun p -> not !was_annotated && encloses_position !display_pos p),true - | DMHover -> (fun p -> not !was_annotated && encloses_position_gt !display_pos p),false - | _ -> (fun p -> not !was_annotated && encloses_position !display_pos p),false - in - let annotate e dk = - was_annotated := true; - (EDisplay(e,dk),pos e) - in - let annotate_marked e = annotate e DKMarked in - let mk_null p = annotate_marked ((EConst(Ident "null")),p) in - let loop_el el = - let pr = DisplayPosition.display_position#with_pos (pos e) in - let rec loop el = match el with - | [] -> [mk_null pr] - | e :: el -> - if (pos e).pmin >= pr.pmax then (mk_null pr) :: e :: el - else e :: loop el - in - (* print_endline (Printf.sprintf "%i-%i: PR" pr.pmin pr.pmax); - List.iter (fun e -> - print_endline (Printf.sprintf "%i-%i: %s" (pos e).pmin (pos e).pmax (Ast.s_expr e)); - ) el; *) - match el with - | [] -> [mk_null pr] - | e :: el -> - if (pos e).pmin >= pr.pmax then (mk_null pr) :: e :: el - else loop (e :: el) - in - let in_pattern = ref false in - let loop e = - (* print_endline (Printf.sprintf "%i-%i: %s" (pos e).pmin (pos e).pmax (Ast.s_expr e)); *) - match fst e with - | EFunction(FKNamed((_,p),_),_) when is_annotated p && is_completion -> - raise Exit - | EVars vl when is_annotated (pos e) && is_completion -> - let rec loop2 acc mark vl = match vl with - | v :: vl -> - if mark then - loop2 (v :: acc) mark vl - else if is_annotated (snd v.ev_name) then - (* If the name is the display position, mark the expression *) - loop2 (v :: acc) true vl - else begin match v.ev_expr with - | None -> - (* If there is no expression, we don't have to do anything. - Should the display position be on the type-hint, it will - be picked up while loading the type. *) - loop2 (v :: acc) mark vl - | Some e -> - (* Determine the area between the `|` in `var x| = | e`. This is not really - correct because we don't want completion on the left side of the `=`, but - we cannot determine that correctly without knowing its position. - Note: We know `e` itself isn't the display position because this entire - algorithm is bottom-up and it would be marked already if it was. *) - let p0 = match v.ev_type with - | Some (_,pt) -> pt - | None -> snd v.ev_name - in - let p = {p0 with pmax = (pos e).pmin} in - let e = if is_annotated p then annotate_marked e else e in - loop2 ({ v with ev_expr = Some e } :: acc) mark vl - end - | [] -> - List.rev acc,mark - in - let vl,mark = loop2 [] false vl in - let e = EVars (List.rev vl),pos e in - if !was_annotated then e else raise Exit - | EBinop((OpAssign | OpAssignOp _) as op,e1,e2) when is_annotated (pos e) && is_completion -> - (* Special case for assign ops: If the expression is marked, but none of its operands are, - we are "probably" interested in the rhs. Like with EVars, this isn't accurate because we - could be on the left side of the `=`. I don't think there's a reason for requesting - completion there though. *) - (EBinop(op,e1,annotate_marked e2)),(pos e) - | EBinop(OpOr,e1,(EIf(_,(EConst(Ident "null"),_),None),p1)) when is_annotated (pos e) && is_completion && !in_pattern -> - (* This HAS TO come from an attempted `case pattern | guard:` completion (issue #7068). *) - let p = { p1 with pmin = (pos e1).pmax; pmax = p1.pmin } in - EBinop(OpOr,e1,mk_null p),(pos e) - | EIf(_,(EConst(Ident "null"),_),None) when is_completion && !in_pattern -> - (* This is fine. *) - mk_null (pos e) - | EBlock [] when is_annotated (pos e) -> - annotate e DKStructure - | EBlock [EDisplay((EConst(Ident s),pn),DKMarked),_] when is_completion -> - let e = EObjectDecl [(s,pn,NoQuotes),(EConst (Ident "null"),null_pos)],(pos e) in - annotate e DKStructure - | EBlock el when is_annotated (pos e) && is_completion -> - let el = loop_el el in - EBlock el,(pos e) - | ECall(e1,el) when is_annotated (pos e) && is_completion -> - let el = loop_el el in - ECall(e1,el),(pos e) - | ENew(ptp,el) when is_annotated (pos e) && is_completion -> - if is_annotated ptp.pos_full || ptp.pos_full.pmax >= (DisplayPosition.display_position#get).pmax then - annotate_marked e - else begin - let el = loop_el el in - ENew(ptp,el),(pos e) - end - | EArrayDecl el when is_annotated (pos e) && is_completion -> - let el = loop_el el in - EArrayDecl el,(pos e) - | EObjectDecl fl when is_annotated (pos e) && is_completion -> - annotate e DKStructure - | ESwitch(e1,cases,def) when is_annotated (pos e) -> - (* We must be "between" two cases, or at the end of the last case. - Let's find the last case which has a position that is < the display - position and mark it. *) - let did_mark = ref false in - let mark_case ec p = - did_mark := true; - let ep = mk_null p in - match ec with - | Some ec -> - let ec = match fst ec with - | EBlock el -> (EBlock (el @ [ep]),p) - | _ -> (EBlock [ec;ep],p) - in - Some ec - | None -> - Some (mk_null p) - in - let rec loop cases = match cases with - | [el,eg,ec,p1] -> - let ec = match def with - | None when (pos e).pmax > !display_pos.pmin -> (* this is so we don't trigger if we're on the } *) - mark_case ec p1 (* no default, must be the last case *) - | Some (_,p2) when p1.pmax <= !display_pos.pmin && p2.pmin >= !display_pos.pmax -> - mark_case ec p1 (* default is beyond display position, mark *) - | _ -> - ec (* default contains display position, don't mark *) - in - [el,eg,ec,p1] - | (el1,eg1,ec1,p1) :: (el2,eg2,ec2,p2) :: cases -> - if p1.pmax <= !display_pos.pmin && p2.pmin >= !display_pos.pmax then - (el1,eg1,mark_case ec1 p1,p1) :: (el2,eg2,ec2,p2) :: cases - else - (el1,eg1,ec1,p1) :: loop ((el2,eg2,ec2,p2) :: cases) - | [] -> - [] - in - let cases = loop cases in - let def = if !did_mark then - def - else match def with - | Some(eo,p) when (pos e).pmax > !display_pos.pmin -> Some (mark_case eo p,p) - | _ -> def - in - ESwitch(e1,cases,def),pos e - | EDisplay _ -> - raise Exit - | EMeta((Meta.Markup,_,_),(EConst(String _),p)) when is_annotated p -> - annotate_marked e - | EConst (String (_,q)) when ((q <> SSingleQuotes) || !Parser.was_auto_triggered) && is_annotated (pos e) && is_completion -> - (* TODO: check if this makes any sense *) - raise Exit - | EConst(Regexp _) when is_annotated (pos e) && is_completion -> - raise Exit - | EVars vl when is_annotated (pos e) -> - (* We only want to mark EVars if we're on a var name. *) - if List.exists (fun v -> is_annotated (snd v.ev_name)) vl then - annotate_marked e - else - raise Exit - | _ -> - if is_annotated (pos e) then - annotate_marked e - else - e - in - let opt f o = - match o with None -> None | Some v -> Some (f v) - in - let rec map e = match fst e with - | ESwitch(e1,cases,def) when is_annotated (pos e) -> - let e1 = map e1 in - let cases = List.map (fun (el,eg,e,p) -> - let old = !in_pattern in - in_pattern := true; - let el = List.map map el in - in_pattern := old; - let eg = opt map eg in - let e = opt map e in - el,eg,e,p - ) cases in - let def = opt (fun (eo,p) -> opt map eo,p) def in - loop (ESwitch (e1, cases, def),(pos e)) - | _ -> - loop (Ast.map_expr map e) - in - try map e with Exit -> e - - let find_display_call e = - let found = ref false in - let handle_el e el = - let call_arg_is_marked () = - el = [] || List.exists (fun (e,_) -> match e with EDisplay(_,DKMarked) -> true | _ -> false) el - in - if not !Parser.was_auto_triggered || call_arg_is_marked () then begin - found := true; - Parser.mk_display_expr e DKCall - end else - e - in - let loop e = match fst e with - | ECall(_,el) | ENew(_,el) when not !found && display_position#enclosed_in (pos e) -> - handle_el e el - | EArray(e1,e2) when not !found && display_position#enclosed_in (pos e2) -> - handle_el e [e2] - | EDisplay(_,DKCall) -> - raise Exit - | _ -> e - in - let rec map e = loop (Ast.map_expr map e) in - try map e with Exit -> e - - - let process_expr com e = match com.display.dms_kind with - | DMDefinition | DMTypeDefinition | DMUsage _ | DMImplementation | DMHover | DMDefault -> find_before_pos com.display.dms_kind e - | DMSignature -> find_display_call e - | _ -> e -end +let preprocess_expr com e = match com.display.dms_kind with + | DMDefinition | DMTypeDefinition | DMUsage _ | DMImplementation | DMHover | DMDefault -> ExprPreprocessing.find_before_pos com.display.dms_kind e + | DMSignature -> ExprPreprocessing.find_display_call e + | _ -> e let get_expected_name with_type = match with_type with | WithType.Value (Some src) | WithType.WithType(_,Some src) -> diff --git a/src/context/display/displayEmitter.ml b/src/context/display/displayEmitter.ml index 681f807736f..e77bdd333c3 100644 --- a/src/context/display/displayEmitter.ml +++ b/src/context/display/displayEmitter.ml @@ -168,7 +168,7 @@ let check_display_metadata ctx meta = if display_position#enclosed_in p then display_meta ctx.com meta p; List.iter (fun e -> if display_position#enclosed_in (pos e) then begin - let e = ExprPreprocessing.process_expr ctx.com e in + let e = preprocess_expr ctx.com e in delay ctx PTypeField (fun _ -> ignore(type_expr ctx e WithType.value)); end ) args diff --git a/src/context/display/exprPreprocessing.ml b/src/context/display/exprPreprocessing.ml new file mode 100644 index 00000000000..2f5f7166028 --- /dev/null +++ b/src/context/display/exprPreprocessing.ml @@ -0,0 +1,224 @@ +open Globals +open Ast +open DisplayTypes.DisplayMode +open DisplayPosition + +let find_before_pos dm e = + let display_pos = ref (DisplayPosition.display_position#get) in + let was_annotated = ref false in + let is_annotated,is_completion = match dm with + | DMDefault -> (fun p -> not !was_annotated && encloses_position !display_pos p),true + | DMHover -> (fun p -> not !was_annotated && encloses_position_gt !display_pos p),false + | _ -> (fun p -> not !was_annotated && encloses_position !display_pos p),false + in + let annotate e dk = + was_annotated := true; + (EDisplay(e,dk),pos e) + in + let annotate_marked e = annotate e DKMarked in + let mk_null p = annotate_marked ((EConst(Ident "null")),p) in + let loop_el el = + let pr = DisplayPosition.display_position#with_pos (pos e) in + let rec loop el = match el with + | [] -> [mk_null pr] + | e :: el -> + if (pos e).pmin >= pr.pmax then (mk_null pr) :: e :: el + else e :: loop el + in + (* print_endline (Printf.sprintf "%i-%i: PR" pr.pmin pr.pmax); + List.iter (fun e -> + print_endline (Printf.sprintf "%i-%i: %s" (pos e).pmin (pos e).pmax (Ast.s_expr e)); + ) el; *) + match el with + | [] -> [mk_null pr] + | e :: el -> + if (pos e).pmin >= pr.pmax then (mk_null pr) :: e :: el + else loop (e :: el) + in + let in_pattern = ref false in + let loop e = + (* print_endline (Printf.sprintf "%i-%i: %s" (pos e).pmin (pos e).pmax (Ast.s_expr e)); *) + match fst e with + | EFunction(FKNamed((_,p),_),_) when is_annotated p && is_completion -> + raise Exit + | EVars vl when is_annotated (pos e) && is_completion -> + let rec loop2 acc mark vl = match vl with + | v :: vl -> + if mark then + loop2 (v :: acc) mark vl + else if is_annotated (snd v.ev_name) then + (* If the name is the display position, mark the expression *) + loop2 (v :: acc) true vl + else begin match v.ev_expr with + | None -> + (* If there is no expression, we don't have to do anything. + Should the display position be on the type-hint, it will + be picked up while loading the type. *) + loop2 (v :: acc) mark vl + | Some e -> + (* Determine the area between the `|` in `var x| = | e`. This is not really + correct because we don't want completion on the left side of the `=`, but + we cannot determine that correctly without knowing its position. + Note: We know `e` itself isn't the display position because this entire + algorithm is bottom-up and it would be marked already if it was. *) + let p0 = match v.ev_type with + | Some (_,pt) -> pt + | None -> snd v.ev_name + in + let p = {p0 with pmax = (pos e).pmin} in + let e = if is_annotated p then annotate_marked e else e in + loop2 ({ v with ev_expr = Some e } :: acc) mark vl + end + | [] -> + List.rev acc,mark + in + let vl,mark = loop2 [] false vl in + let e = EVars (List.rev vl),pos e in + if !was_annotated then e else raise Exit + | EBinop((OpAssign | OpAssignOp _) as op,e1,e2) when is_annotated (pos e) && is_completion -> + (* Special case for assign ops: If the expression is marked, but none of its operands are, + we are "probably" interested in the rhs. Like with EVars, this isn't accurate because we + could be on the left side of the `=`. I don't think there's a reason for requesting + completion there though. *) + (EBinop(op,e1,annotate_marked e2)),(pos e) + | EBinop(OpOr,e1,(EIf(_,(EConst(Ident "null"),_),None),p1)) when is_annotated (pos e) && is_completion && !in_pattern -> + (* This HAS TO come from an attempted `case pattern | guard:` completion (issue #7068). *) + let p = { p1 with pmin = (pos e1).pmax; pmax = p1.pmin } in + EBinop(OpOr,e1,mk_null p),(pos e) + | EIf(_,(EConst(Ident "null"),_),None) when is_completion && !in_pattern -> + (* This is fine. *) + mk_null (pos e) + | EBlock [] when is_annotated (pos e) -> + annotate e DKStructure + | EBlock [EDisplay((EConst(Ident s),pn),DKMarked),_] when is_completion -> + let e = EObjectDecl [(s,pn,NoQuotes),(EConst (Ident "null"),null_pos)],(pos e) in + annotate e DKStructure + | EBlock el when is_annotated (pos e) && is_completion -> + let el = loop_el el in + EBlock el,(pos e) + | ECall(e1,el) when is_annotated (pos e) && is_completion -> + let el = loop_el el in + ECall(e1,el),(pos e) + | ENew(ptp,el) when is_annotated (pos e) && is_completion -> + if is_annotated ptp.pos_full || ptp.pos_full.pmax >= (DisplayPosition.display_position#get).pmax then + annotate_marked e + else begin + let el = loop_el el in + ENew(ptp,el),(pos e) + end + | EArrayDecl el when is_annotated (pos e) && is_completion -> + let el = loop_el el in + EArrayDecl el,(pos e) + | EObjectDecl fl when is_annotated (pos e) && is_completion -> + annotate e DKStructure + | ESwitch(e1,cases,def) when is_annotated (pos e) -> + (* We must be "between" two cases, or at the end of the last case. + Let's find the last case which has a position that is < the display + position and mark it. *) + let did_mark = ref false in + let mark_case ec p = + did_mark := true; + let ep = mk_null p in + match ec with + | Some ec -> + let ec = match fst ec with + | EBlock el -> (EBlock (el @ [ep]),p) + | _ -> (EBlock [ec;ep],p) + in + Some ec + | None -> + Some (mk_null p) + in + let rec loop cases = match cases with + | [el,eg,ec,p1] -> + let ec = match def with + | None when (pos e).pmax > !display_pos.pmin -> (* this is so we don't trigger if we're on the } *) + mark_case ec p1 (* no default, must be the last case *) + | Some (_,p2) when p1.pmax <= !display_pos.pmin && p2.pmin >= !display_pos.pmax -> + mark_case ec p1 (* default is beyond display position, mark *) + | _ -> + ec (* default contains display position, don't mark *) + in + [el,eg,ec,p1] + | (el1,eg1,ec1,p1) :: (el2,eg2,ec2,p2) :: cases -> + if p1.pmax <= !display_pos.pmin && p2.pmin >= !display_pos.pmax then + (el1,eg1,mark_case ec1 p1,p1) :: (el2,eg2,ec2,p2) :: cases + else + (el1,eg1,ec1,p1) :: loop ((el2,eg2,ec2,p2) :: cases) + | [] -> + [] + in + let cases = loop cases in + let def = if !did_mark then + def + else match def with + | Some(eo,p) when (pos e).pmax > !display_pos.pmin -> Some (mark_case eo p,p) + | _ -> def + in + ESwitch(e1,cases,def),pos e + | EDisplay _ -> + raise Exit + | EMeta((Meta.Markup,_,_),(EConst(String _),p)) when is_annotated p -> + annotate_marked e + | EConst (String (_,q)) when ((q <> SSingleQuotes) || !Parser.was_auto_triggered) && is_annotated (pos e) && is_completion -> + (* TODO: check if this makes any sense *) + raise Exit + | EConst(Regexp _) when is_annotated (pos e) && is_completion -> + raise Exit + | EVars vl when is_annotated (pos e) -> + (* We only want to mark EVars if we're on a var name. *) + if List.exists (fun v -> is_annotated (snd v.ev_name)) vl then + annotate_marked e + else + raise Exit + | _ -> + if is_annotated (pos e) then + annotate_marked e + else + e + in + let opt f o = + match o with None -> None | Some v -> Some (f v) + in + let rec map e = match fst e with + | ESwitch(e1,cases,def) when is_annotated (pos e) -> + let e1 = map e1 in + let cases = List.map (fun (el,eg,e,p) -> + let old = !in_pattern in + in_pattern := true; + let el = List.map map el in + in_pattern := old; + let eg = opt map eg in + let e = opt map e in + el,eg,e,p + ) cases in + let def = opt (fun (eo,p) -> opt map eo,p) def in + loop (ESwitch (e1, cases, def),(pos e)) + | _ -> + loop (Ast.map_expr map e) + in + try map e with Exit -> e + +let find_display_call e = + let found = ref false in + let handle_el e el = + let call_arg_is_marked () = + el = [] || List.exists (fun (e,_) -> match e with EDisplay(_,DKMarked) -> true | _ -> false) el + in + if not !Parser.was_auto_triggered || call_arg_is_marked () then begin + found := true; + Parser.mk_display_expr e DKCall + end else + e + in + let loop e = match fst e with + | ECall(_,el) | ENew(_,el) when not !found && display_position#enclosed_in (pos e) -> + handle_el e el + | EArray(e1,e2) when not !found && display_position#enclosed_in (pos e2) -> + handle_el e [e2] + | EDisplay(_,DKCall) -> + raise Exit + | _ -> e + in + let rec map e = loop (Ast.map_expr map e) in + try map e with Exit -> e \ No newline at end of file diff --git a/src/context/formatString.ml b/src/context/formatString.ml new file mode 100644 index 00000000000..69d255f58fd --- /dev/null +++ b/src/context/formatString.ml @@ -0,0 +1,98 @@ +open Globals +open Ast + +let format_string defines s p process_expr = + let e = ref None in + let pmin = ref p.pmin in + let min = ref (p.pmin + 1) in + let add_expr (enext,p) len = + min := !min + len; + let enext = process_expr enext p in + match !e with + | None -> e := Some enext + | Some prev -> + e := Some (EBinop (OpAdd,prev,enext),punion (pos prev) p) + in + let add enext len = + let p = { p with pmin = !min; pmax = !min + len } in + add_expr (enext,p) len + in + let add_sub start pos = + let len = pos - start in + if len > 0 || !e = None then add (EConst (String (String.sub s start len,SDoubleQuotes))) len + in + let len = String.length s in + let rec parse start pos = + if pos = len then add_sub start pos else + let c = String.unsafe_get s pos in + let pos = pos + 1 in + if c = '\'' then begin + incr pmin; + incr min; + end; + if c <> '$' || pos = len then parse start pos else + match String.unsafe_get s pos with + | '$' -> + (* double $ *) + add_sub start pos; + parse (pos + 1) (pos + 1) + | '{' -> + parse_group start pos '{' '}' "brace" + | 'a'..'z' | 'A'..'Z' | '_' -> + add_sub start (pos - 1); + incr min; + let rec loop i = + if i = len then i else + let c = String.unsafe_get s i in + match c with + | 'a'..'z' | 'A'..'Z' | '0'..'9' | '_' -> loop (i+1) + | _ -> i + in + let iend = loop (pos + 1) in + let len = iend - pos in + add (EConst (Ident (String.sub s pos len))) len; + parse (pos + len) (pos + len) + | _ -> + (* keep as-it *) + parse start pos + and parse_group start pos gopen gclose gname = + add_sub start (pos - 1); + let rec loop groups i = + if i = len then + match groups with + | [] -> die "" __LOC__ + | g :: _ -> Error.raise_typing_error ("Unclosed " ^ gname) { p with pmin = !pmin + g + 1; pmax = !pmin + g + 2 } + else + let c = String.unsafe_get s i in + if c = gopen then + loop (i :: groups) (i + 1) + else if c = gclose then begin + let groups = List.tl groups in + if groups = [] then i else loop groups (i + 1) + end else + loop groups (i + 1) + in + let send = loop [pos] (pos + 1) in + let slen = send - pos - 1 in + let scode = String.sub s (pos + 1) slen in + min := !min + 2; + begin + let e = + let ep = { p with pmin = !pmin + pos + 2; pmax = !pmin + send + 1 } in + let error msg pos = + if Lexer.string_is_whitespace scode then Error.raise_typing_error "Expression cannot be empty" ep + else Error.raise_typing_error msg pos + in + match ParserEntry.parse_expr_string defines scode ep error true with + | ParseSuccess(data,_,_) -> data + | ParseError(_,(msg,p),_) -> error (Parser.error_msg msg) p + in + add_expr e slen + end; + min := !min + 1; + parse (send + 1) (send + 1) + in + parse 0 0; + match !e with + | None -> die "" __LOC__ + | Some e -> e diff --git a/src/context/memory.ml b/src/context/memory.ml index 8d16ca17ffe..58eab29cdc5 100644 --- a/src/context/memory.ml +++ b/src/context/memory.ml @@ -122,8 +122,8 @@ let get_memory_json (cs : CompilationCache.t) mreq = "nativeLibCache",jint (mem_size cache_mem.(3)); "additionalSizes",jarray [ jobject ["name",jstring "macro interpreter";"size",jint (mem_size (MacroContext.macro_interp_cache))]; - jobject ["name",jstring "macro stdlib";"size",jint (mem_size (EvalContext.GlobalState.stdlib))]; - jobject ["name",jstring "macro macro_lib";"size",jint (mem_size (EvalContext.GlobalState.macro_lib))]; + (* jobject ["name",jstring "macro stdlib";"size",jint (mem_size (EvalContext.GlobalState.stdlib))]; + jobject ["name",jstring "macro macro_lib";"size",jint (mem_size (EvalContext.GlobalState.macro_lib))]; *) jobject ["name",jstring "last completion result";"size",jint (mem_size (DisplayException.last_completion_result))]; jobject ["name",jstring "Lexer file cache";"size",jint (mem_size (Lexer.all_files))]; jobject ["name",jstring "GC heap words";"size",jint (int_of_float size)]; diff --git a/src/context/typecore.ml b/src/context/typecore.ml index f0fcded97f9..9597863c742 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -23,6 +23,7 @@ open Common open Type open Error open Resolution +open FieldCallCandidate type type_patch = { mutable tp_type : complex_type option; @@ -98,7 +99,8 @@ type typer_globals = { retain_meta : bool; mutable core_api : typer option; mutable macros : ((unit -> unit) * typer) option; - mutable std : module_def; + mutable std : tclass; + mutable std_types : module_def; type_patches : (path, (string * bool, type_patch) Hashtbl.t * type_patch) Hashtbl.t; mutable module_check_policies : (string list * module_check_policy list * bool) list; mutable global_using : (tclass * pos) list; @@ -162,24 +164,6 @@ and monomorphs = { mutable perfunction : (tmono * pos) list; } -(* This record holds transient information about an (attempted) call on a field. It is created when resolving - field calls and is passed to overload filters. *) -type 'a field_call_candidate = { - (* The argument expressions for this call and whether or not the argument is optional on the - target function. *) - fc_args : texpr list; - (* The applied return type. *) - fc_ret : Type.t; - (* The applied function type. *) - fc_type : Type.t; - (* The class field being called. *) - fc_field : tclass_field; - (* The field monomorphs that were created for this call. *) - fc_monos : Type.t list; - (* The custom data associated with this call. *) - fc_data : 'a; -} - type field_host = | FHStatic of tclass | FHInstance of tclass * tparams @@ -698,26 +682,6 @@ let safe_mono_close ctx m p = Unify_error l -> raise_or_display ctx l p -let make_field_call_candidate args ret monos t cf data = { - fc_args = args; - fc_type = t; - fc_field = cf; - fc_data = data; - fc_ret = ret; - fc_monos = monos; -} - -let s_field_call_candidate fcc = - let pctx = print_context() in - let se = s_expr_pretty false "" false (s_type pctx) in - let sl_args = List.map se fcc.fc_args in - Printer.s_record_fields "" [ - "fc_args",String.concat ", " sl_args; - "fc_type",s_type pctx fcc.fc_type; - "fc_field",Printf.sprintf "%s: %s" fcc.fc_field.cf_name (s_type pctx fcc.fc_field.cf_type) - ] - - let relative_path ctx file = let slashes path = String.concat "/" (ExtString.String.nsplit path "\\") in let fpath = slashes (Path.get_full_path file) in diff --git a/src/core/naming.ml b/src/core/naming.ml new file mode 100644 index 00000000000..05b9bedb4ef --- /dev/null +++ b/src/core/naming.ml @@ -0,0 +1,88 @@ +open Globals +open Ast +open Meta +open Type +open Error + +(** retrieve string from @:native metadata or raise Not_found *) +let get_native_name meta = + let rec get_native meta = match meta with + | [] -> raise Not_found + | (Meta.Native,[v],p as meta) :: _ -> + meta + | _ :: meta -> + get_native meta + in + let (_,e,mp) = get_native meta in + match e with + | [Ast.EConst (Ast.String(name,_)),p] -> + name,p + | [] -> + raise Not_found + | _ -> + Error.raise_typing_error "String expected" mp + +(* Rewrites class or enum paths if @:native metadata is set *) +let apply_native_paths t = + let get_real_name meta name = + let name',p = get_native_name meta in + (Meta.RealPath,[Ast.EConst (Ast.String (name,SDoubleQuotes)), p], p), name' + in + let get_real_path meta path = + let name,p = get_native_name meta in + (Meta.RealPath,[Ast.EConst (Ast.String (s_type_path path,SDoubleQuotes)), p], p), parse_path name + in + try + (match t with + | TClassDecl c -> + let did_change = ref false in + let field cf = try + let meta,name = get_real_name cf.cf_meta cf.cf_name in + cf.cf_name <- name; + cf.cf_meta <- meta :: cf.cf_meta; + List.iter (fun cf -> cf.cf_name <- name) cf.cf_overloads; + did_change := true + with Not_found -> + () + in + let fields cfs old_map = + did_change := false; + List.iter field cfs; + if !did_change then + List.fold_left (fun map f -> PMap.add f.cf_name f map) PMap.empty cfs + else + old_map + in + c.cl_fields <- fields c.cl_ordered_fields c.cl_fields; + c.cl_statics <- fields c.cl_ordered_statics c.cl_statics; + let meta,path = get_real_path c.cl_meta c.cl_path in + c.cl_meta <- meta :: c.cl_meta; + c.cl_path <- path; + | TEnumDecl e -> + let did_change = ref false in + let field _ ef = try + let meta,name = get_real_name ef.ef_meta ef.ef_name in + ef.ef_name <- name; + ef.ef_meta <- meta :: ef.ef_meta; + did_change := true; + with Not_found -> + () + in + PMap.iter field e.e_constrs; + if !did_change then begin + let names = ref [] in + e.e_constrs <- PMap.fold + (fun ef map -> + names := ef.ef_name :: !names; + PMap.add ef.ef_name ef map + ) + e.e_constrs PMap.empty; + e.e_names <- !names; + end; + let meta,path = get_real_path e.e_meta e.e_path in + e.e_meta <- meta :: e.e_meta; + e.e_path <- path; + | _ -> + ()) + with Not_found -> + () \ No newline at end of file diff --git a/src/core/socket.ml b/src/core/socket.ml index 58888134db8..f037c3e6a6c 100644 --- a/src/core/socket.ml +++ b/src/core/socket.ml @@ -37,6 +37,17 @@ let read_string socket = let _ = recv socket buf 0 i [] in Bytes.to_string buf +let write_byte this i v = + Bytes.set this i (Char.unsafe_chr v) + +let write_i32 this i v = + let base = Int32.to_int v in + let big = Int32.to_int (Int32.shift_right_logical v 24) in + write_byte this i base; + write_byte this (i + 1) (base lsr 8); + write_byte this (i + 2) (base lsr 16); + write_byte this (i + 3) big + let send_string socket s = match socket.socket with | None -> @@ -45,7 +56,7 @@ let send_string socket s = let b = Bytes.unsafe_of_string s in let l = Bytes.length b in let buf = Bytes.make 4 ' ' in - EvalBytes.write_i32 buf 0 (Int32.of_int l); + write_i32 buf 0 (Int32.of_int l); ignore(send socket buf 0 4 []); let rec loop length offset = if length <= 0 then diff --git a/src/filters/addFieldInits.ml b/src/filters/addFieldInits.ml new file mode 100644 index 00000000000..91e302294b1 --- /dev/null +++ b/src/filters/addFieldInits.ml @@ -0,0 +1,68 @@ +open Globals +open Common +open Type + + +let add_field_inits cl_path locals com t = + let apply c = + let ethis = mk (TConst TThis) (TInst (c,extract_param_types c.cl_params)) c.cl_pos in + (* TODO: we have to find a variable name which is not used in any of the functions *) + let v = alloc_var VGenerated "_g" ethis.etype ethis.epos in + let need_this = ref false in + let inits,fields = List.fold_left (fun (inits,fields) cf -> + match cf.cf_kind,cf.cf_expr with + | Var _, Some _ -> (cf :: inits, cf :: fields) + | _ -> (inits, cf :: fields) + ) ([],[]) c.cl_ordered_fields in + c.cl_ordered_fields <- (List.rev fields); + match inits with + | [] -> () + | _ -> + let el = List.map (fun cf -> + match cf.cf_expr with + | None -> die "" __LOC__ + | Some e -> + let lhs = mk (TField({ ethis with epos = cf.cf_pos },FInstance (c,extract_param_types c.cl_params,cf))) cf.cf_type cf.cf_pos in + cf.cf_expr <- None; + mk (TBinop(OpAssign,lhs,e)) cf.cf_type e.epos + ) inits in + let el = if !need_this then (mk (TVar((v, Some ethis))) ethis.etype ethis.epos) :: el else el in + let cf = match c.cl_constructor with + | None -> + let ct = TFun([],com.basic.tvoid) in + let ce = mk (TFunction { + tf_args = []; + tf_type = com.basic.tvoid; + tf_expr = mk (TBlock el) com.basic.tvoid c.cl_pos; + }) ct c.cl_pos in + let ctor = mk_field "new" ct c.cl_pos null_pos in + ctor.cf_kind <- Method MethNormal; + { ctor with cf_expr = Some ce } + | Some cf -> + match cf.cf_expr with + | Some { eexpr = TFunction f } -> + let bl = match f.tf_expr with {eexpr = TBlock b } -> b | x -> [x] in + let ce = mk (TFunction {f with tf_expr = mk (TBlock (el @ bl)) com.basic.tvoid c.cl_pos }) cf.cf_type cf.cf_pos in + {cf with cf_expr = Some ce }; + | _ -> + die "" __LOC__ + in + let config = AnalyzerConfig.get_field_config com c cf in + remove_class_field_flag cf CfPostProcessed; + Analyzer.Run.run_on_field com config c cf; + add_class_field_flag cf CfPostProcessed; + (match cf.cf_expr with + | Some e -> + (* This seems a bit expensive, but hopefully constructor expressions aren't that massive. *) + let e = RenameVars.run cl_path locals e in + let e = Optimizer.sanitize com e in + cf.cf_expr <- Some e + | _ -> + ()); + c.cl_constructor <- Some cf + in + match t with + | TClassDecl c -> + apply c + | _ -> + () \ No newline at end of file diff --git a/src/filters/exceptionFunctions.ml b/src/filters/exceptionFunctions.ml new file mode 100644 index 00000000000..8c6d061a41c --- /dev/null +++ b/src/filters/exceptionFunctions.ml @@ -0,0 +1,22 @@ +open Type + +let haxe_exception_type_path = (["haxe"],"Exception") +let value_exception_type_path = (["haxe"],"ValueException") + +(** + Check if `cls` is or extends (if `check_parent=true`) `haxe.Exception` +*) + let rec is_haxe_exception_class ?(check_parent=true) cls = + cls.cl_path = haxe_exception_type_path + || (check_parent && match cls.cl_super with + | None -> false + | Some (cls, _) -> is_haxe_exception_class ~check_parent cls + ) + + (** + Check if `t` is or extends `haxe.Exception` + *) + let is_haxe_exception ?(check_parent=true) (t:Type.t) = + match Abstract.follow_with_abstracts t with + | TInst (cls, _) -> is_haxe_exception_class ~check_parent cls + | _ -> false \ No newline at end of file diff --git a/src/filters/exceptions.ml b/src/filters/exceptions.ml index 40be2a218ce..98003ee7e9f 100644 --- a/src/filters/exceptions.ml +++ b/src/filters/exceptions.ml @@ -4,9 +4,7 @@ open Type open Common open Typecore open Error - -let haxe_exception_type_path = (["haxe"],"Exception") -let value_exception_type_path = (["haxe"],"ValueException") +open ExceptionFunctions type context = { typer : typer; @@ -65,11 +63,7 @@ let haxe_exception_instance_call ctx haxe_exception method_name args p = *) let std_is ctx e t p = let t = follow t in - let std_cls = - match Typeload.load_type_raise ctx.typer ([],"Std") "Std" p with - | TClassDecl cls -> cls - | _ -> raise_typing_error "Std is expected to be a class" p - in + let std_cls = ctx.typer.g.std in let isOfType_field = try PMap.find "isOfType" std_cls.cl_statics with Not_found -> raise_typing_error ("Std has no field isOfType") p @@ -122,23 +116,6 @@ let is_haxe_wildcard_catch ctx t = let t = Abstract.follow_with_abstracts t in t == t_dynamic || fast_eq ctx.haxe_exception_type t -(** - Check if `cls` is or extends (if `check_parent=true`) `haxe.Exception` -*) -let rec is_haxe_exception_class ?(check_parent=true) cls = - cls.cl_path = haxe_exception_type_path - || (check_parent && match cls.cl_super with - | None -> false - | Some (cls, _) -> is_haxe_exception_class ~check_parent cls - ) - -(** - Check if `t` is or extends `haxe.Exception` -*) -let is_haxe_exception ?(check_parent=true) (t:Type.t) = - match Abstract.follow_with_abstracts t with - | TInst (cls, _) -> is_haxe_exception_class ~check_parent cls - | _ -> false (** Check if `v` variable is used in `e` expression diff --git a/src/filters/filters.ml b/src/filters/filters.ml index 37f5bc5ec5e..e3ab6478d7c 100644 --- a/src/filters/filters.ml +++ b/src/filters/filters.ml @@ -25,7 +25,7 @@ open Error open Globals open FiltersCommon -let get_native_name = TypeloadCheck.get_native_name +let get_native_name = Naming.get_native_name (* PASS 1 begin *) @@ -66,66 +66,6 @@ let rec add_final_return e = { e with eexpr = TFunction f } | _ -> e -module LocalStatic = struct - let promote_local_static ctx lut v eo = - let name = Printf.sprintf "%s_%s" ctx.curfield.cf_name v.v_name in - begin try - let cf = PMap.find name ctx.curclass.cl_statics in - display_error ctx.com (Printf.sprintf "The expanded name of this local (%s) conflicts with another static field" name) v.v_pos; - raise_typing_error ~depth:1 "Conflicting field was found here" cf.cf_name_pos; - 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 -> - () - | Some e -> - let rec loop e = match e.eexpr with - | TLocal _ | TFunction _ -> - raise_typing_error "Accessing local variables in static initialization is not allowed" e.epos - | TConst (TThis | TSuper) -> - raise_typing_error "Accessing `this` in static initialization is not allowed" e.epos - | TReturn _ | TBreak | TContinue -> - raise_typing_error "This kind of control flow in static initialization is not allowed" e.epos - | _ -> - iter loop e - in - loop e; - cf.cf_expr <- Some e - end; - TClass.add_field ctx.curclass cf; - Hashtbl.add lut v.v_id cf - end - - let find_local_static lut v = - Hashtbl.find lut v.v_id - - let run ctx e = - let local_static_lut = Hashtbl.create 0 in - let c = ctx.curclass in - let rec run e = match e.eexpr with - | TBlock el -> - let el = ExtList.List.filter_map (fun e -> match e.eexpr with - | TVar(v,eo) when has_var_flag v VStatic -> - promote_local_static ctx local_static_lut v eo; - None - | _ -> - Some (run e) - ) el in - { e with eexpr = TBlock el } - | TLocal v when has_var_flag v VStatic -> - begin try - let cf = find_local_static local_static_lut v in - Texpr.Builder.make_static_field c cf e.epos - with Not_found -> - raise_typing_error (Printf.sprintf "Could not find local static %s (id %i)" v.v_name v.v_id) e.epos - end - | _ -> - Type.map_expr run e - in - run e -end - (* -------------------------------------------------------------------------- *) (* CHECK LOCAL VARS INIT *) @@ -356,12 +296,6 @@ let check_abstract_as_value e = (* PASS 2 begin *) -let remove_generic_base t = match t with - | TClassDecl c when is_removable_class c -> - add_class_flag c CExtern; - | _ -> - () - (* Removes extern and macro fields, also checks for Void fields *) let remove_extern_fields com t = match t with @@ -393,71 +327,6 @@ let check_private_path com t = match t with | _ -> () -(* Rewrites class or enum paths if @:native metadata is set *) -let apply_native_paths t = - let get_real_name meta name = - let name',p = get_native_name meta in - (Meta.RealPath,[Ast.EConst (Ast.String (name,SDoubleQuotes)), p], p), name' - in - let get_real_path meta path = - let name,p = get_native_name meta in - (Meta.RealPath,[Ast.EConst (Ast.String (s_type_path path,SDoubleQuotes)), p], p), parse_path name - in - try - (match t with - | TClassDecl c -> - let did_change = ref false in - let field cf = try - let meta,name = get_real_name cf.cf_meta cf.cf_name in - cf.cf_name <- name; - cf.cf_meta <- meta :: cf.cf_meta; - List.iter (fun cf -> cf.cf_name <- name) cf.cf_overloads; - did_change := true - with Not_found -> - () - in - let fields cfs old_map = - did_change := false; - List.iter field cfs; - if !did_change then - List.fold_left (fun map f -> PMap.add f.cf_name f map) PMap.empty cfs - else - old_map - in - c.cl_fields <- fields c.cl_ordered_fields c.cl_fields; - c.cl_statics <- fields c.cl_ordered_statics c.cl_statics; - let meta,path = get_real_path c.cl_meta c.cl_path in - c.cl_meta <- meta :: c.cl_meta; - c.cl_path <- path; - | TEnumDecl e -> - let did_change = ref false in - let field _ ef = try - let meta,name = get_real_name ef.ef_meta ef.ef_name in - ef.ef_name <- name; - ef.ef_meta <- meta :: ef.ef_meta; - did_change := true; - with Not_found -> - () - in - PMap.iter field e.e_constrs; - if !did_change then begin - let names = ref [] in - e.e_constrs <- PMap.fold - (fun ef map -> - names := ef.ef_name :: !names; - PMap.add ef.ef_name ef map - ) - e.e_constrs PMap.empty; - e.e_names <- !names; - end; - let meta,path = get_real_path e.e_meta e.e_path in - e.e_meta <- meta :: e.e_meta; - e.e_path <- path; - | _ -> - ()) - with Not_found -> - () - (* Adds the __rtti field if required *) let add_rtti com t = let rec has_rtti c = @@ -473,71 +342,6 @@ let add_rtti com t = | _ -> () -(* Adds member field initializations as assignments to the constructor *) -let add_field_inits cl_path locals com t = - let apply c = - let ethis = mk (TConst TThis) (TInst (c,extract_param_types c.cl_params)) c.cl_pos in - (* TODO: we have to find a variable name which is not used in any of the functions *) - let v = alloc_var VGenerated "_g" ethis.etype ethis.epos in - let need_this = ref false in - let inits,fields = List.fold_left (fun (inits,fields) cf -> - match cf.cf_kind,cf.cf_expr with - | Var _, Some _ -> (cf :: inits, cf :: fields) - | _ -> (inits, cf :: fields) - ) ([],[]) c.cl_ordered_fields in - c.cl_ordered_fields <- (List.rev fields); - match inits with - | [] -> () - | _ -> - let el = List.map (fun cf -> - match cf.cf_expr with - | None -> die "" __LOC__ - | Some e -> - let lhs = mk (TField({ ethis with epos = cf.cf_pos },FInstance (c,extract_param_types c.cl_params,cf))) cf.cf_type cf.cf_pos in - cf.cf_expr <- None; - mk (TBinop(OpAssign,lhs,e)) cf.cf_type e.epos - ) inits in - let el = if !need_this then (mk (TVar((v, Some ethis))) ethis.etype ethis.epos) :: el else el in - let cf = match c.cl_constructor with - | None -> - let ct = TFun([],com.basic.tvoid) in - let ce = mk (TFunction { - tf_args = []; - tf_type = com.basic.tvoid; - tf_expr = mk (TBlock el) com.basic.tvoid c.cl_pos; - }) ct c.cl_pos in - let ctor = mk_field "new" ct c.cl_pos null_pos in - ctor.cf_kind <- Method MethNormal; - { ctor with cf_expr = Some ce } - | Some cf -> - match cf.cf_expr with - | Some { eexpr = TFunction f } -> - let bl = match f.tf_expr with {eexpr = TBlock b } -> b | x -> [x] in - let ce = mk (TFunction {f with tf_expr = mk (TBlock (el @ bl)) com.basic.tvoid c.cl_pos }) cf.cf_type cf.cf_pos in - {cf with cf_expr = Some ce }; - | _ -> - die "" __LOC__ - in - let config = AnalyzerConfig.get_field_config com c cf in - remove_class_field_flag cf CfPostProcessed; - Analyzer.Run.run_on_field com config c cf; - add_class_field_flag cf CfPostProcessed; - (match cf.cf_expr with - | Some e -> - (* This seems a bit expensive, but hopefully constructor expressions aren't that massive. *) - let e = RenameVars.run cl_path locals e in - let e = Optimizer.sanitize com e in - cf.cf_expr <- Some e - | _ -> - ()); - c.cl_constructor <- Some cf - in - match t with - | TClassDecl c -> - apply c - | _ -> - () - (* Adds the __meta__ field if required *) let add_meta_field com t = match t with | TClassDecl c -> @@ -667,14 +471,6 @@ let check_reserved_type_paths com t = (* PASS 3 end *) -let is_cached com t = - let m = (t_infos t).mt_module.m_extra in - m.m_processed <> 0 && m.m_processed < com.compilation_step - -let apply_filters_once ctx filters t = - let detail_times = (try int_of_string (Common.defined_value_safe ctx.com ~default:"0" Define.FilterTimes) with _ -> 0) in - if not (is_cached ctx.com t) then run_expression_filters ctx detail_times filters t - let iter_expressions fl mt = match mt with | TClassDecl c -> @@ -715,7 +511,7 @@ let destruction tctx detail_times main locals = with_timer detail_times "type 2" None (fun () -> (* PASS 2: type filters pre-DCE *) List.iter (fun t -> - remove_generic_base t; + FiltersCommon.remove_generic_base t; remove_extern_fields com t; (* check @:remove metadata before DCE so it is ignored there (issue #2923) *) check_remove_metadata t; @@ -747,9 +543,9 @@ let destruction tctx detail_times main locals = let type_filters = [ Exceptions.patch_constructors tctx; (* TODO: I don't believe this should load_instance anything at this point... *) check_private_path com; - apply_native_paths; + Naming.apply_native_paths; add_rtti com; - (match com.platform with | Java | Cs -> (fun _ -> ()) | _ -> (fun mt -> add_field_inits tctx.curclass.cl_path locals com mt)); + (match com.platform with | Java | Cs -> (fun _ -> ()) | _ -> (fun mt -> AddFieldInits.add_field_inits tctx.curclass.cl_path locals com mt)); (match com.platform with Hl -> (fun _ -> ()) | _ -> add_meta_field com); check_void_field; (match com.platform with | Cpp -> promote_first_interface_to_super | _ -> (fun _ -> ())); diff --git a/src/filters/filtersCommon.ml b/src/filters/filtersCommon.ml index aa862dd718d..0905404f2f4 100644 --- a/src/filters/filtersCommon.ml +++ b/src/filters/filtersCommon.ml @@ -18,6 +18,7 @@ *) open Globals open Type +open Common open Typecore let rec is_removable_class c = @@ -36,6 +37,12 @@ let rec is_removable_class c = | _ -> false +let remove_generic_base t = match t with + | TClassDecl c when is_removable_class c -> + add_class_flag c CExtern; + | _ -> + () + (** Check if `field` is overridden in subclasses *) @@ -82,3 +89,11 @@ let run_expression_filters ?(ignore_processed_status=false) ctx detail_times fil | TEnumDecl _ -> () | TTypeDecl _ -> () | TAbstractDecl _ -> () + +let is_cached com t = + let m = (t_infos t).mt_module.m_extra in + m.m_processed <> 0 && m.m_processed < com.compilation_step + +let apply_filters_once ctx filters t = + let detail_times = (try int_of_string (Common.defined_value_safe ctx.com ~default:"0" Define.FilterTimes) with _ -> 0) in + if not (is_cached ctx.com t) then run_expression_filters ctx detail_times filters t \ No newline at end of file diff --git a/src/filters/localStatic.ml b/src/filters/localStatic.ml new file mode 100644 index 00000000000..ce1f5dbaf9b --- /dev/null +++ b/src/filters/localStatic.ml @@ -0,0 +1,63 @@ +open Global +open Common +open Type +open Typecore +open Error + +let promote_local_static ctx lut v eo = + let name = Printf.sprintf "%s_%s" ctx.curfield.cf_name v.v_name in + begin try + let cf = PMap.find name ctx.curclass.cl_statics in + display_error ctx.com (Printf.sprintf "The expanded name of this local (%s) conflicts with another static field" name) v.v_pos; + raise_typing_error ~depth:1 "Conflicting field was found here" cf.cf_name_pos; + 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 -> + () + | Some e -> + let rec loop e = match e.eexpr with + | TLocal _ | TFunction _ -> + raise_typing_error "Accessing local variables in static initialization is not allowed" e.epos + | TConst (TThis | TSuper) -> + raise_typing_error "Accessing `this` in static initialization is not allowed" e.epos + | TReturn _ | TBreak | TContinue -> + raise_typing_error "This kind of control flow in static initialization is not allowed" e.epos + | _ -> + iter loop e + in + loop e; + cf.cf_expr <- Some e + end; + TClass.add_field ctx.curclass cf; + Hashtbl.add lut v.v_id cf + end + +let find_local_static lut v = + Hashtbl.find lut v.v_id + +let run ctx e = + let local_static_lut = Hashtbl.create 0 in + let c = ctx.curclass in + let rec run e = match e.eexpr with + | TBlock el -> + let el = ExtList.List.filter_map (fun e -> match e.eexpr with + | TVar(v,eo) when has_var_flag v VStatic -> + promote_local_static ctx local_static_lut v eo; + None + | _ -> + Some (run e) + ) el in + { e with eexpr = TBlock el } + | TLocal v when has_var_flag v VStatic -> + begin try + let cf = find_local_static local_static_lut v in + Texpr.Builder.make_static_field c cf e.epos + with Not_found -> + raise_typing_error (Printf.sprintf "Could not find local static %s (id %i)" v.v_name v.v_id) e.epos + end + | _ -> + Type.map_expr run e + in + run e \ No newline at end of file diff --git a/src/filters/renameVars.ml b/src/filters/renameVars.ml index b7c8b882c3e..5306ccd9ff9 100644 --- a/src/filters/renameVars.ml +++ b/src/filters/renameVars.ml @@ -28,17 +28,17 @@ let reserve_init ri name = let reserve_all_types ri com path_to_name = List.iter (fun mt -> let tinfos = t_infos mt in - let native_name = try fst (TypeloadCheck.get_native_name tinfos.mt_meta) with Not_found -> path_to_name tinfos.mt_path in + let native_name = try fst (Naming.get_native_name tinfos.mt_meta) with Not_found -> path_to_name tinfos.mt_path in match mt with | TClassDecl c when native_name = "" -> List.iter (fun cf -> - let native_name = try fst (TypeloadCheck.get_native_name cf.cf_meta) with Not_found -> cf.cf_name in + let native_name = try fst (Naming.get_native_name cf.cf_meta) with Not_found -> cf.cf_name in reserve_init ri native_name ) c.cl_ordered_statics | TClassDecl { cl_kind = KModuleFields m; cl_ordered_statics = fl } -> let prefix = Path.flat_path m.m_path ^ "_" in List.iter (fun cf -> - let name = try fst (TypeloadCheck.get_native_name cf.cf_meta) with Not_found -> prefix ^ cf.cf_name in + let name = try fst (Naming.get_native_name cf.cf_meta) with Not_found -> prefix ^ cf.cf_name in reserve_init ri name ) fl | _ -> diff --git a/src/generators/genjs.ml b/src/generators/genjs.ml index 37ef20c887c..02a90e3427d 100644 --- a/src/generators/genjs.ml +++ b/src/generators/genjs.ml @@ -154,13 +154,13 @@ let static_field ctx c f = let module_field m f = try - fst (TypeloadCheck.get_native_name f.cf_meta) + fst (Naming.get_native_name f.cf_meta) with Not_found -> Path.flat_path m.m_path ^ "_" ^ f.cf_name let module_field_expose_path mpath f = try - fst (TypeloadCheck.get_native_name f.cf_meta) + fst (Naming.get_native_name f.cf_meta) with Not_found -> (dot_path mpath) ^ "." ^ f.cf_name diff --git a/src/generators/genjvm.ml b/src/generators/genjvm.ml index 1fa8a737d7e..6e6c7e358e6 100644 --- a/src/generators/genjvm.ml +++ b/src/generators/genjvm.ml @@ -395,7 +395,7 @@ let is_interface_var_access c cf = let follow = Abstract.follow_with_abstracts class haxe_exception gctx (t : Type.t) = - let is_haxe_exception = Exceptions.is_haxe_exception t + let is_haxe_exception = ExceptionFunctions.is_haxe_exception t and native_type = jsignature_of_type gctx t in object(self) val native_path = (match native_type with TObject(path,_) -> path | _ -> die "" __LOC__) @@ -2134,7 +2134,7 @@ class texpr_to_jvm self#texpr rvalue_any e1; (* There could be something like `throw throw`, so we should only throw if we aren't terminated (issue #10363) *) if not (jm#is_terminated) then begin - if not (Exceptions.is_haxe_exception e1.etype) && not (does_unify e1.etype gctx.t_runtime_exception) then begin + if not (ExceptionFunctions.is_haxe_exception e1.etype) && not (does_unify e1.etype gctx.t_runtime_exception) then begin let exc = new haxe_exception gctx e1.etype in if not (List.exists (fun exc' -> exc#is_assignable_to exc') caught_exceptions) then jm#add_thrown_exception exc#get_native_path; diff --git a/src/generators/genswf9.ml b/src/generators/genswf9.ml index b689717e5fc..d34ba33fc47 100644 --- a/src/generators/genswf9.ml +++ b/src/generators/genswf9.ml @@ -1066,7 +1066,7 @@ let rec gen_expr_content ctx retval e = gen_constant ctx c e.etype e.epos | TThrow e -> ctx.infos.icond <- true; - if has_feature ctx.com "haxe.CallStack.exceptionStack" && not (Exceptions.is_haxe_exception e.etype) then begin + if has_feature ctx.com "haxe.CallStack.exceptionStack" && not (ExceptionFunctions.is_haxe_exception e.etype) then begin getvar ctx (VGlobal (type_path ctx (["flash"],"Boot"))); let id = type_path ctx (["flash";"errors"],"Error") in write ctx (HFindPropStrict id); @@ -1240,7 +1240,7 @@ let rec gen_expr_content ctx retval e = | _ -> Type.iter call_loop e in let has_call = (try call_loop e; false with Exit -> true) in - if has_call && has_feature ctx.com "haxe.CallStack.exceptionStack" && not (Exceptions.is_haxe_exception v.v_type) then begin + if has_call && has_feature ctx.com "haxe.CallStack.exceptionStack" && not (ExceptionFunctions.is_haxe_exception v.v_type) then begin getvar ctx (gen_local_access ctx v e.epos Read); write ctx (HAsType (type_path ctx (["flash";"errors"],"Error"))); let j = jump ctx J3False in diff --git a/src/macro/eval/eval.ml b/src/macro/eval/eval.ml new file mode 100644 index 00000000000..132547972ab --- /dev/null +++ b/src/macro/eval/eval.ml @@ -0,0 +1,5 @@ +include EvalEncode +include EvalDecode +include EvalValue +include EvalContext +include EvalMain \ No newline at end of file diff --git a/src/macro/eval/evalContext.ml b/src/macro/eval/evalContext.ml index 9842d4c321d..9249f6f3034 100644 --- a/src/macro/eval/evalContext.ml +++ b/src/macro/eval/evalContext.ml @@ -302,11 +302,6 @@ module GlobalState = struct let stdlib : builtins option ref = ref None let macro_lib : (string,value) Hashtbl.t = Hashtbl.create 0 - - let cleanup ctx = - (* curapi holds a reference to the typing context which we don't want to persist. Let's unset it so the - context can be collected. *) - ctx.curapi <- Obj.magic "" end let get_ctx () = (!GlobalState.get_ctx_ref)() diff --git a/src/macro/eval/evalDebugSocket.ml b/src/macro/eval/evalDebugSocket.ml index 2d135169ef8..55be0d1cb98 100644 --- a/src/macro/eval/evalDebugSocket.ml +++ b/src/macro/eval/evalDebugSocket.ml @@ -486,7 +486,7 @@ module ValueCompletion = struct DisplayPosition.display_position#set {p with pmin = offset; pmax = offset}; begin try let e = parse_expr ctx text p in - let e = Display.ExprPreprocessing.find_before_pos DMDefault e in + let e = ExprPreprocessing.find_before_pos DMDefault e in save(); let rec loop e = match fst e with | EDisplay(e1,DKDot) -> diff --git a/src/macro/eval/evalExceptions.ml b/src/macro/eval/evalExceptions.ml index 6603195dcd7..f1c146d98d6 100644 --- a/src/macro/eval/evalExceptions.ml +++ b/src/macro/eval/evalExceptions.ml @@ -27,7 +27,6 @@ open EvalField exception Break exception Continue exception Return of value -exception Sys_exit of int let s_value_kind = function | VNull -> "VNull" diff --git a/src/macro/eval/evalMain.ml b/src/macro/eval/evalMain.ml index 20db1dbf6d3..a69afdef6a6 100644 --- a/src/macro/eval/evalMain.ml +++ b/src/macro/eval/evalMain.ml @@ -145,7 +145,8 @@ let create com api is_macro = Which is printing an error to stderr and exiting with code 2 *) Luv.Error.set_on_unhandled_exception (fun ex -> match ex with - | Sys_exit _ -> raise ex + | EvalTypes.Sys_exit _ -> + raise ex | _ -> let msg = match ex with | Error.Error err -> diff --git a/src/macro/eval/evalStdLib.ml b/src/macro/eval/evalStdLib.ml index ae09bcbfef8..7cdb911bb58 100644 --- a/src/macro/eval/evalStdLib.ml +++ b/src/macro/eval/evalStdLib.ml @@ -2590,7 +2590,7 @@ module StdSys = struct ) let exit = vfun1 (fun code -> - raise (Sys_exit(decode_int code)); + raise (EvalTypes.Sys_exit(decode_int code)); ) let getChar = vfun1 (fun echo -> diff --git a/src/macro/eval/evalThread.ml b/src/macro/eval/evalThread.ml index 708b7e9e350..6230122a3cb 100644 --- a/src/macro/eval/evalThread.ml +++ b/src/macro/eval/evalThread.ml @@ -100,7 +100,7 @@ let run ctx f thread = let msg = get_exc_error_message ctx v stack p in prerr_endline msg; close(); - | Sys_exit i -> + | EvalTypes.Sys_exit i -> close(); exit i; | exc -> diff --git a/src/macro/eval/evalTypes.ml b/src/macro/eval/evalTypes.ml new file mode 100644 index 00000000000..8f8c2a11887 --- /dev/null +++ b/src/macro/eval/evalTypes.ml @@ -0,0 +1 @@ +exception Sys_exit of int \ No newline at end of file diff --git a/src/optimization/inline.ml b/src/optimization/inline.ml index d953b689a4f..a51f6a1d8b4 100644 --- a/src/optimization/inline.ml +++ b/src/optimization/inline.ml @@ -6,6 +6,8 @@ open Common open Typecore open Error +let maybe_reapply_overload_call_ref = ref (fun _ _ -> assert false) + let mk_untyped_call name p params = { eexpr = TCall({ eexpr = TIdent name; etype = t_dynamic; epos = p }, params); @@ -627,7 +629,7 @@ class inline_state ctx ethis params cf f p = object(self) else map_type in let e = Type.map_expr_type (map_expr_type map_type) map_type (map_var map_type) e in - CallUnification.maybe_reapply_overload_call ctx e + (!maybe_reapply_overload_call_ref) ctx e in let e = map_expr_type map_type e in let rec drop_unused_vars e = diff --git a/src/typing/callUnification.ml b/src/typing/callUnification.ml index a5d82477854..913beb90c2f 100644 --- a/src/typing/callUnification.ml +++ b/src/typing/callUnification.ml @@ -5,6 +5,7 @@ open Common open Typecore open Error open FieldAccess +open FieldCallCandidate let unify_call_args ctx el args r callp inline force_inline in_overload = let call_error err p = raise_error_msg (Call_error err) p in diff --git a/src/typing/fieldCallCandidate.ml b/src/typing/fieldCallCandidate.ml new file mode 100644 index 00000000000..e43a68226c9 --- /dev/null +++ b/src/typing/fieldCallCandidate.ml @@ -0,0 +1,39 @@ + +open Type + +(* This record holds transient information about an (attempted) call on a field. It is created when resolving + field calls and is passed to overload filters. *) + type 'a field_call_candidate = { + (* The argument expressions for this call and whether or not the argument is optional on the + target function. *) + fc_args : texpr list; + (* The applied return type. *) + fc_ret : Type.t; + (* The applied function type. *) + fc_type : Type.t; + (* The class field being called. *) + fc_field : tclass_field; + (* The field monomorphs that were created for this call. *) + fc_monos : Type.t list; + (* The custom data associated with this call. *) + fc_data : 'a; +} + +let make_field_call_candidate args ret monos t cf data = { + fc_args = args; + fc_type = t; + fc_field = cf; + fc_data = data; + fc_ret = ret; + fc_monos = monos; +} + +let s_field_call_candidate fcc = + let pctx = print_context() in + let se = s_expr_pretty false "" false (s_type pctx) in + let sl_args = List.map se fcc.fc_args in + Printer.s_record_fields "" [ + "fc_args",String.concat ", " sl_args; + "fc_type",s_type pctx fcc.fc_type; + "fc_field",Printf.sprintf "%s: %s" fcc.fc_field.cf_name (s_type pctx fcc.fc_field.cf_type) + ] diff --git a/src/typing/functionArguments.ml b/src/typing/functionArguments.ml index 80c9c161a75..4baf7402020 100644 --- a/src/typing/functionArguments.ml +++ b/src/typing/functionArguments.ml @@ -22,7 +22,7 @@ let type_function_arg_value ctx t c do_display = | None -> None | Some e -> let p = pos e in - let e = if do_display then Display.ExprPreprocessing.process_expr ctx.com e else e in + let e = if do_display then Display.preprocess_expr ctx.com e else e in let e = Optimizer.reduce_expression ctx (type_expr ctx e (WithType.with_type t)) in unify ctx e.etype t p; let rec loop e = match e.eexpr with diff --git a/src/typing/generic.ml b/src/typing/generic.ml index 70bc96890d7..c9dcf4d3713 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -5,6 +5,7 @@ open Ast open Type open Typecore open Error +open FieldCallCandidate type generic_context = { ctx : typer; diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index be211c9f133..96a3c07e5ff 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -26,14 +26,6 @@ open Resolution open Error open Globals -module Eval = struct - include EvalEncode - include EvalDecode - include EvalValue - include EvalContext - include EvalMain -end - module InterpImpl = Eval (* Hlmacro *) module Interp = struct @@ -48,7 +40,7 @@ let macro_interp_cache = ref None let safe_decode com v expected t p f = try f () - with MacroApi.Invalid_expr | EvalContext.RunTimeException _ -> + with MacroApi.Invalid_expr -> let path = [dump_path com;"decoding_error"] in let ch = Path.create_file false ".txt" [] path in let errors = Interp.handle_decoding_error (output_string ch) v t in @@ -282,7 +274,7 @@ let make_macro_com_api com mcom p = !macro_enable_cache ); format_string = (fun s p -> - Common.format_string com s p (fun e p -> (e,p)) + FormatString.format_string com.defines s p (fun e p -> (e,p)) ); cast_or_unify = (fun t e p -> Interp.exc_string "unsupported" @@ -632,7 +624,7 @@ and flush_macro_context mint mctx = (* we should maybe ensure that all filters in Main are applied. Not urgent atm *) let expr_filters = [ "handle_abstract_casts",AbstractCast.handle_abstract_casts mctx; - "local_statics",Filters.LocalStatic.run mctx; + "local_statics",LocalStatic.run mctx; "Exceptions",Exceptions.filter mctx; "captured_vars",CapturedVars.captured_vars mctx.com; ] in @@ -668,14 +660,14 @@ and flush_macro_context mint mctx = () in let type_filters = [ - Filters.remove_generic_base; + FiltersCommon.remove_generic_base; Exceptions.patch_constructors mctx; - (fun mt -> Filters.add_field_inits mctx.curclass.cl_path (RenameVars.init mctx.com) mctx.com mt); + (fun mt -> AddFieldInits.add_field_inits mctx.curclass.cl_path (RenameVars.init mctx.com) mctx.com mt); minimal_restore; - Filters.apply_native_paths + Naming.apply_native_paths ] in let ready = fun t -> - Filters.apply_filters_once mctx expr_filters t; + FiltersCommon.apply_filters_once mctx expr_filters t; List.iter (fun f -> f t) type_filters in (try Interp.add_types mint types ready @@ -996,7 +988,7 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p = else try let ct = Interp.decode_ctype v in Typeload.load_complex_type ctx false ct; - with MacroApi.Invalid_expr | EvalContext.RunTimeException _ -> + with MacroApi.Invalid_expr | EvalContext.RunTimeException _ -> Interp.decode_type v in ctx.ret <- t; diff --git a/src/typing/overloadResolution.ml b/src/typing/overloadResolution.ml index bd16f135f02..456623bbf09 100644 --- a/src/typing/overloadResolution.ml +++ b/src/typing/overloadResolution.ml @@ -1,7 +1,7 @@ -open Typecore open TType open TUnification open TFunctions +open FieldCallCandidate let unify_cf map_type c cf el = let monos = List.map (fun _ -> mk_mono()) cf.cf_params in diff --git a/src/typing/typeload.ml b/src/typing/typeload.ml index 66ee7d44d8a..04b98056ffd 100644 --- a/src/typing/typeload.ml +++ b/src/typing/typeload.ml @@ -102,17 +102,6 @@ let find_type_in_module_raise ctx m tname p = with Not_found -> raise_typing_error_ext (make_error (Type_not_found (m.m_path,tname,Not_defined)) p) -(* raises Module_not_found or Type_not_found *) -let load_type_raise ctx mpath tname p = - let m = ctx.g.do_load_module ctx mpath p in - find_type_in_module_raise ctx m tname p - -(* raises Not_found *) -let load_type ctx mpath tname p = try - load_type_raise ctx mpath tname p -with Error { err_message = (Module_not_found _ | Type_not_found _); err_pos = p2 } when p = p2 -> - raise Not_found - (** since load_type_def and load_instance are used in PASS2, they should not access the structure of a type **) let find_type_in_current_module_context ctx pack name = diff --git a/src/typing/typeloadCheck.ml b/src/typing/typeloadCheck.ml index a144dcace14..e343c1414e2 100644 --- a/src/typing/typeloadCheck.ml +++ b/src/typing/typeloadCheck.ml @@ -130,24 +130,6 @@ let copy_meta meta_src meta_target sl = ) meta_src; !meta -(** retrieve string from @:native metadata or raise Not_found *) -let get_native_name meta = - let rec get_native meta = match meta with - | [] -> raise Not_found - | (Meta.Native,[v],p as meta) :: _ -> - meta - | _ :: meta -> - get_native meta - in - let (_,e,mp) = get_native meta in - match e with - | [Ast.EConst (Ast.String(name,_)),p] -> - name,p - | [] -> - raise Not_found - | _ -> - raise_typing_error "String expected" mp - let check_native_name_override ctx child base = let error base_pos child_pos = (* TODO construct error *) @@ -155,9 +137,9 @@ let check_native_name_override ctx child base = display_error ~depth:1 ctx.com (compl_msg "Base field is defined here") base_pos in try - let child_name, child_pos = get_native_name child.cf_meta in + let child_name, child_pos = Naming.get_native_name child.cf_meta in try - let base_name, base_pos = get_native_name base.cf_meta in + let base_name, base_pos = Naming.get_native_name base.cf_meta in if base_name <> child_name then error base_pos child_pos with Not_found -> diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index f95f6fbe888..a0536851016 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -706,7 +706,7 @@ let transform_field (ctx,cctx) c f fields p = let type_var_field ctx t e stat do_display p = if stat then ctx.curfun <- FunStatic else ctx.curfun <- FunMember; - let e = if do_display then Display.ExprPreprocessing.process_expr ctx.com e else e in + let e = if do_display then Display.preprocess_expr ctx.com e else e in let e = type_expr ctx e (WithType.with_type t) in let e = AbstractCast.cast_or_unify ctx t e p in match t with diff --git a/src/typing/typeloadFunction.ml b/src/typing/typeloadFunction.ml index 175540be1ca..3709c1798d2 100644 --- a/src/typing/typeloadFunction.ml +++ b/src/typing/typeloadFunction.ml @@ -78,7 +78,7 @@ let type_function ctx (args : function_arguments) ret fmode e do_display p = end else begin let is_display_debug = Meta.has (Meta.Custom ":debug.display") ctx.curfield.cf_meta in if is_display_debug then print_endline ("before processing:\n" ^ (Expr.dump_with_pos e)); - let e = if !Parser.had_resume then e else Display.ExprPreprocessing.process_expr ctx.com e in + let e = if !Parser.had_resume then e else Display.preprocess_expr ctx.com e in if is_display_debug then print_endline ("after processing:\n" ^ (Expr.dump_with_pos e)); type_expr ctx e NoValue end in diff --git a/src/typing/typeloadModule.ml b/src/typing/typeloadModule.ml index a12549deee7..4a10021b50c 100644 --- a/src/typing/typeloadModule.ml +++ b/src/typing/typeloadModule.ml @@ -707,7 +707,7 @@ let make_curmod ctx m = let rl = new resolution_list ["import";s_type_path m.m_path] in List.iter (fun mt -> rl#add (module_type_resolution mt None null_pos)) - (List.rev ctx.g.std.m_types); + (List.rev ctx.g.std_types.m_types); { curmod = m; import_resolution = rl; @@ -764,8 +764,8 @@ let type_types_into_module ctx m tdecls p = List.iter (TypeloadCheck.check_module_types ctx m p) types; m.m_types <- m.m_types @ types; (* define the per-module context for the next pass *) - if ctx.g.std != null_module then begin - add_dependency m ctx.g.std; + if ctx.g.std_types != null_module then begin + add_dependency m ctx.g.std_types; (* this will ensure both String and (indirectly) Array which are basic types which might be referenced *) ignore(load_instance ctx (make_ptp (mk_type_path (["std"],"String")) null_pos) ParamNormal) end; diff --git a/src/typing/typer.ml b/src/typing/typer.ml index f8f69f69da9..31438deb0b2 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -750,9 +750,9 @@ and type_vars ctx vl p = mk (TMeta((Meta.MergeBlock,[],p), e)) e.etype e.epos and format_string ctx s p = - Common.format_string ctx.com s p (fun enext p -> + FormatString.format_string ctx.com.defines s p (fun enext p -> if ctx.in_display && DisplayPosition.display_position#enclosed_in p then - Display.ExprPreprocessing.process_expr ctx.com (enext,p) + Display.preprocess_expr ctx.com (enext,p) else enext,p ) @@ -2015,160 +2015,18 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) = DisplayEmitter.display_module_type ctx mt p_t; let e_t = type_module_type ctx mt p_t in let e_Std_isOfType = - match Typeload.load_type_raise ctx ([],"Std") "Std" p with - | TClassDecl c -> - let cf = - try PMap.find "isOfType" c.cl_statics - with Not_found -> die "" __LOC__ - in - Texpr.Builder.make_static_field c cf (mk_zero_range_pos p) - | _ -> die "" __LOC__ + ignore(ctx.g.std.cl_build()); + let cf = try + PMap.find "isOfType" ctx.g.std.cl_statics + with Not_found -> + die "" __LOC__ + in + Texpr.Builder.make_static_field ctx.g.std cf (mk_zero_range_pos p) in mk (TCall (e_Std_isOfType, [e; e_t])) ctx.com.basic.tbool p | _ -> display_error ctx.com "Unsupported type for `is` operator" p_t; Texpr.Builder.make_bool ctx.com.basic false p - -(* ---------------------------------------------------------------------- *) -(* TYPER INITIALIZATION *) - -let create com macros = - let ctx = { - com = com; - t = com.basic; - g = { - core_api = None; - macros = macros; - type_patches = Hashtbl.create 0; - module_check_policies = []; - delayed = []; - debug_delayed = []; - doinline = com.display.dms_inline && not (Common.defined com Define.NoInline); - retain_meta = Common.defined com Define.RetainUntypedMeta; - std = null_module; - global_using = []; - complete = false; - type_hints = []; - load_only_cached_modules = false; - functional_interface_lut = new pmap_lookup; - do_macro = MacroContext.type_macro; - do_load_macro = MacroContext.load_macro'; - do_load_module = TypeloadModule.load_module; - do_load_type_def = Typeload.load_type_def; - get_build_info = InstanceBuilder.get_build_info; - do_format_string = format_string; - do_load_core_class = Typeload.load_core_class; - }; - m = { - curmod = null_module; - import_resolution = new resolution_list ["import";"typer"]; - own_resolution = None; - enum_with_type = None; - module_using = []; - import_statements = []; - }; - is_display_file = false; - bypass_accessor = 0; - meta = []; - with_type_stack = []; - call_argument_stack = []; - pass = PBuildModule; - macro_depth = 0; - untyped = false; - curfun = FunStatic; - in_function = false; - in_loop = false; - in_display = false; - allow_inline = true; - allow_transform = true; - get_build_infos = (fun() -> None); - ret = mk_mono(); - locals = PMap.empty; - type_params = []; - curclass = null_class; - curfield = null_field; - tthis = mk_mono(); - opened = []; - vthis = None; - in_call_args = false; - in_overload_call_args = false; - delayed_display = None; - monomorphs = { - perfunction = []; - }; - memory_marker = Typecore.memory_marker; - } in - ctx.g.std <- (try - TypeloadModule.load_module ctx ([],"StdTypes") null_pos - with - Error { err_message = Module_not_found ([],"StdTypes") } -> - try - let std_path = Sys.getenv "HAXE_STD_PATH" in - raise_typing_error ("Standard library not found. Please check your `HAXE_STD_PATH` environment variable (current value: \"" ^ std_path ^ "\")") null_pos - with Not_found -> - raise_typing_error "Standard library not found. You may need to set your `HAXE_STD_PATH` environment variable" null_pos - ); - (* We always want core types to be available so we add them as default imports (issue #1904 and #3131). *) - List.iter (fun mt -> - ctx.m.import_resolution#add (module_type_resolution mt None null_pos)) - (List.rev ctx.g.std.m_types); - List.iter (fun t -> - match t with - | TAbstractDecl a -> - (match snd a.a_path with - | "Void" -> ctx.t.tvoid <- TAbstract (a,[]); - | "Float" -> ctx.t.tfloat <- TAbstract (a,[]); - | "Int" -> ctx.t.tint <- TAbstract (a,[]) - | "Bool" -> ctx.t.tbool <- TAbstract (a,[]) - | "Dynamic" -> t_dynamic_def := TAbstract(a,extract_param_types a.a_params); - | "Null" -> - let mk_null t = - try - if not (is_null ~no_lazy:true t || is_explicit_null t) then TAbstract (a,[t]) else t - with Exit -> - (* don't force lazy evaluation *) - let r = ref (lazy_available t_dynamic) in - r := lazy_wait (fun() -> - let t = (if not (is_null t) then TAbstract (a,[t]) else t) in - r := lazy_available t; - t - ); - TLazy r - in - ctx.t.tnull <- mk_null; - | _ -> ()) - | TEnumDecl _ | TClassDecl _ | TTypeDecl _ -> - () - ) ctx.g.std.m_types; - let m = TypeloadModule.load_module ctx ([],"String") null_pos in - List.iter (fun mt -> match mt with - | TClassDecl c -> ctx.t.tstring <- TInst (c,[]) - | _ -> () - ) m.m_types; - let m = TypeloadModule.load_module ctx ([],"Array") null_pos in - (try - List.iter (fun t -> ( - match t with - | TClassDecl ({cl_path = ([],"Array")} as c) -> - ctx.t.tarray <- (fun t -> TInst (c,[t])); - raise Exit - | _ -> () - )) m.m_types; - die "" __LOC__ - with Exit -> ()); - let m = TypeloadModule.load_module ctx (["haxe"],"EnumTools") null_pos in - (match m.m_types with - | [TClassDecl c1;TClassDecl c2] -> ctx.g.global_using <- (c1,c1.cl_pos) :: (c2,c2.cl_pos) :: ctx.g.global_using - | [TClassDecl c1] -> - let m = TypeloadModule.load_module ctx (["haxe"],"EnumWithType.valueTools") null_pos in - (match m.m_types with - | [TClassDecl c2 ] -> ctx.g.global_using <- (c1,c1.cl_pos) :: (c2,c2.cl_pos) :: ctx.g.global_using - | _ -> die "" __LOC__); - | _ -> die "" __LOC__); - ignore(TypeloadModule.load_module ctx (["haxe"],"Exception") null_pos); - ctx.g.complete <- true; - ctx - ;; unify_min_ref := unify_min; unify_min_for_type_source_ref := unify_min_for_type_source; @@ -2176,5 +2034,4 @@ make_call_ref := make_call; type_call_target_ref := type_call_target; type_access_ref := type_access; type_block_ref := type_block; -create_context_ref := create; type_expr_ref := (fun ?(mode=MGet) ctx e with_type -> type_expr ~mode ctx e with_type); diff --git a/src/typing/typerEntry.ml b/src/typing/typerEntry.ml new file mode 100644 index 00000000000..f7a854fd3c5 --- /dev/null +++ b/src/typing/typerEntry.ml @@ -0,0 +1,154 @@ +open Globals +open Common +open Type +open Typecore +open Typer +open Resolution +open Error + +let create com macros = + let ctx = { + com = com; + t = com.basic; + g = { + core_api = None; + macros = macros; + type_patches = Hashtbl.create 0; + module_check_policies = []; + delayed = []; + debug_delayed = []; + doinline = com.display.dms_inline && not (Common.defined com Define.NoInline); + retain_meta = Common.defined com Define.RetainUntypedMeta; + std_types = null_module; + std = null_class; + global_using = []; + complete = false; + type_hints = []; + load_only_cached_modules = false; + functional_interface_lut = new pmap_lookup; + do_macro = MacroContext.type_macro; + do_load_macro = MacroContext.load_macro'; + do_load_module = TypeloadModule.load_module; + do_load_type_def = Typeload.load_type_def; + get_build_info = InstanceBuilder.get_build_info; + do_format_string = format_string; + do_load_core_class = Typeload.load_core_class; + }; + m = { + curmod = null_module; + import_resolution = new resolution_list ["import";"typer"]; + own_resolution = None; + enum_with_type = None; + module_using = []; + import_statements = []; + }; + is_display_file = false; + bypass_accessor = 0; + meta = []; + with_type_stack = []; + call_argument_stack = []; + pass = PBuildModule; + macro_depth = 0; + untyped = false; + curfun = FunStatic; + in_function = false; + in_loop = false; + in_display = false; + allow_inline = true; + allow_transform = true; + get_build_infos = (fun() -> None); + ret = mk_mono(); + locals = PMap.empty; + type_params = []; + curclass = null_class; + curfield = null_field; + tthis = mk_mono(); + opened = []; + vthis = None; + in_call_args = false; + in_overload_call_args = false; + delayed_display = None; + monomorphs = { + perfunction = []; + }; + memory_marker = Typecore.memory_marker; + } in + ctx.g.std_types <- (try + TypeloadModule.load_module ctx ([],"StdTypes") null_pos + with + Error { err_message = Module_not_found ([],"StdTypes") } -> + try + let std_path = Sys.getenv "HAXE_STD_PATH" in + raise_typing_error ("Standard library not found. Please check your `HAXE_STD_PATH` environment variable (current value: \"" ^ std_path ^ "\")") null_pos + with Not_found -> + raise_typing_error "Standard library not found. You may need to set your `HAXE_STD_PATH` environment variable" null_pos + ); + (* We always want core types to be available so we add them as default imports (issue #1904 and #3131). *) + List.iter (fun mt -> + ctx.m.import_resolution#add (module_type_resolution mt None null_pos)) + (List.rev ctx.g.std_types.m_types); + List.iter (fun t -> + match t with + | TAbstractDecl a -> + (match snd a.a_path with + | "Void" -> ctx.t.tvoid <- TAbstract (a,[]); + | "Float" -> ctx.t.tfloat <- TAbstract (a,[]); + | "Int" -> ctx.t.tint <- TAbstract (a,[]) + | "Bool" -> ctx.t.tbool <- TAbstract (a,[]) + | "Dynamic" -> t_dynamic_def := TAbstract(a,extract_param_types a.a_params); + | "Null" -> + let mk_null t = + try + if not (is_null ~no_lazy:true t || is_explicit_null t) then TAbstract (a,[t]) else t + with Exit -> + (* don't force lazy evaluation *) + let r = ref (lazy_available t_dynamic) in + r := lazy_wait (fun() -> + let t = (if not (is_null t) then TAbstract (a,[t]) else t) in + r := lazy_available t; + t + ); + TLazy r + in + ctx.t.tnull <- mk_null; + | _ -> ()) + | TEnumDecl _ | TClassDecl _ | TTypeDecl _ -> + () + ) ctx.g.std_types.m_types; + let m = TypeloadModule.load_module ctx ([],"String") null_pos in + List.iter (fun mt -> match mt with + | TClassDecl c -> ctx.t.tstring <- TInst (c,[]) + | _ -> () + ) m.m_types; + let m = TypeloadModule.load_module ctx ([],"Std") null_pos in + List.iter (fun mt -> match mt with + | TClassDecl c -> ctx.g.std <- c; + | _ -> () + ) m.m_types; + let m = TypeloadModule.load_module ctx ([],"Array") null_pos in + (try + List.iter (fun t -> ( + match t with + | TClassDecl ({cl_path = ([],"Array")} as c) -> + ctx.t.tarray <- (fun t -> TInst (c,[t])); + raise Exit + | _ -> () + )) m.m_types; + die "" __LOC__ + with Exit -> ()); + let m = TypeloadModule.load_module ctx (["haxe"],"EnumTools") null_pos in + (match m.m_types with + | [TClassDecl c1;TClassDecl c2] -> ctx.g.global_using <- (c1,c1.cl_pos) :: (c2,c2.cl_pos) :: ctx.g.global_using + | [TClassDecl c1] -> + let m = TypeloadModule.load_module ctx (["haxe"],"EnumWithType.valueTools") null_pos in + (match m.m_types with + | [TClassDecl c2 ] -> ctx.g.global_using <- (c1,c1.cl_pos) :: (c2,c2.cl_pos) :: ctx.g.global_using + | _ -> die "" __LOC__); + | _ -> die "" __LOC__); + ignore(TypeloadModule.load_module ctx (["haxe"],"Exception") null_pos); + ctx.g.complete <- true; + ctx + +;; +create_context_ref := create; +Inline.maybe_reapply_overload_call_ref := CallUnification.maybe_reapply_overload_call; \ No newline at end of file From db4e612a1fb37a247a2a39c974290215b77f3274 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 27 Dec 2023 16:48:43 +0100 Subject: [PATCH 042/184] respect anon_status when identifying --- src/typing/tanon_identification.ml | 54 +++++++++++++++++++----------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/src/typing/tanon_identification.ml b/src/typing/tanon_identification.ml index 8af805fe9ee..4e76f5c4152 100644 --- a/src/typing/tanon_identification.ml +++ b/src/typing/tanon_identification.ml @@ -135,29 +135,26 @@ object(self) 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) -> + method identity_anon (an : tanon) = + let make_pfm path = { + pfm_path = path; + pfm_params = []; + pfm_fields = an.a_fields; + pfm_converted = None; + pfm_arity = count_fields an.a_fields; + } in + match !(an.a_status) with + | ClassStatics {cl_path = path} | EnumStatics {e_path = path} | AbstractStatics {a_path = path} -> + let pfm = make_pfm path in + self#add_pfm path pfm; + Some pfm + | _ -> 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) + Some (self#find_compatible arity (TAnon an)) with Not_found -> let id = num in num <- num + 1; @@ -171,7 +168,26 @@ object(self) } in self#add_pfm path pfm; Some pfm - end; + end + + 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) -> + self#identity_anon an | _ -> None end \ No newline at end of file From 6f8f567db7c0eb10faa062f909c11d3a17411805 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 27 Dec 2023 19:34:17 +0100 Subject: [PATCH 043/184] [typer] purge all rogue ClassStatics --- src/codegen/codegen.ml | 10 ++---- src/context/typecore.ml | 6 +--- src/core/tFunctions.ml | 15 ++++++++ src/core/tOther.ml | 56 +++++++++++++++++++++++------- src/core/texpr.ml | 9 +++-- src/generators/genpy.ml | 3 +- src/optimization/inline.ml | 4 +-- src/typing/finalization.ml | 2 +- src/typing/tanon_identification.ml | 10 ++++-- 9 files changed, 76 insertions(+), 39 deletions(-) diff --git a/src/codegen/codegen.ml b/src/codegen/codegen.ml index 0fb322c9f88..a40ab712126 100644 --- a/src/codegen/codegen.ml +++ b/src/codegen/codegen.ml @@ -419,16 +419,10 @@ end *) let default_cast ?(vtmp="$t") com e texpr t p = let api = com.basic in - let mk_texpr = function - | TClassDecl c -> mk_anon (ref (ClassStatics c)) - | TEnumDecl e -> mk_anon (ref (EnumStatics e)) - | TAbstractDecl a -> mk_anon (ref (AbstractStatics a)) - | TTypeDecl _ -> die "" __LOC__ - in let vtmp = alloc_var VGenerated vtmp e.etype e.epos in let var = mk (TVar (vtmp,Some e)) api.tvoid p in let vexpr = mk (TLocal vtmp) e.etype p in - let texpr = mk (TTypeExpr texpr) (mk_texpr texpr) p in + let texpr = Texpr.Builder.make_typeexpr texpr p in let std = (try List.find (fun t -> t_path t = ([],"Std")) com.types with Not_found -> die "" __LOC__) in let fis = (try let c = (match std with TClassDecl c -> c | _ -> die "" __LOC__) in @@ -436,7 +430,7 @@ let default_cast ?(vtmp="$t") com e texpr t p = with Not_found -> die "" __LOC__ ) in - let std = mk (TTypeExpr std) (mk_texpr std) p in + let std = Texpr.Builder.make_typeexpr std p in let is = mk (TField (std,fis)) (tfun [t_dynamic;t_dynamic] api.tbool) p in let is = mk (TCall (is,[vexpr;texpr])) api.tbool p in let enull = Texpr.Builder.make_null vexpr.etype p in diff --git a/src/context/typecore.ml b/src/context/typecore.ml index 9597863c742..56769dad5c6 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -257,12 +257,8 @@ let spawn_monomorph' ctx p = let spawn_monomorph ctx p = TMono (spawn_monomorph' ctx p) -let make_static_this c p = - let ta = mk_anon ~fields:c.cl_statics (ref (ClassStatics c)) in - mk (TTypeExpr (TClassDecl c)) ta p - let make_static_field_access c cf t p = - let ethis = make_static_this c p in + let ethis = Texpr.Builder.make_static_this c p in mk (TField (ethis,(FStatic (c,cf)))) t p let make_static_call ctx c cf map args t p = diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index 9f3240a37f0..cea0faabb0c 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -878,3 +878,18 @@ let var_extra params e = { v_params = params; v_expr = e; } + +let class_module_type c = + let path = ([],"Class<" ^ (s_type_path c.cl_path) ^ ">") in + let t = mk_anon ~fields:c.cl_statics (ref (ClassStatics c)) in + { (mk_typedef c.cl_module path c.cl_pos null_pos t) with t_private = true} + +let enum_module_type m path p = + let path = ([], "Enum<" ^ (s_type_path path) ^ ">") in + let t = mk_mono() in + {(mk_typedef m path p null_pos t) with t_private = true} + +let abstract_module_type a tl = + let path = ([],Printf.sprintf "Abstract<%s>" (s_type_path a.a_path)) in + let t = mk_anon (ref (AbstractStatics a)) in + {(mk_typedef a.a_module path a.a_pos null_pos t) with t_private = true} diff --git a/src/core/tOther.ml b/src/core/tOther.ml index dcb5c2b9ea7..2366b731a9a 100644 --- a/src/core/tOther.ml +++ b/src/core/tOther.ml @@ -263,20 +263,50 @@ end let no_meta = [] -let class_module_type c = - let path = ([],"Class<" ^ (s_type_path c.cl_path) ^ ">") in - let t = mk_anon ~fields:c.cl_statics (ref (ClassStatics c)) in - { (mk_typedef c.cl_module path c.cl_pos null_pos t) with t_private = true} +let mk_enum m path pos name_pos = + { + e_path = path; + e_module = m; + e_pos = pos; + e_name_pos = name_pos; + e_doc = None; + e_meta = []; + e_params = []; + e_using = []; + e_restore = (fun () -> ()); + e_private = false; + e_extern = false; + e_constrs = PMap.empty; + e_names = []; + e_type = enum_module_type m path pos; + } -let enum_module_type m path p = - let path = ([], "Enum<" ^ (s_type_path path) ^ ">") in - let t = mk_mono() in - {(mk_typedef m path p null_pos t) with t_private = true} - -let abstract_module_type a tl = - let path = ([],Printf.sprintf "Abstract<%s%s>" (s_type_path a.a_path) (s_type_params (ref []) tl)) in - let t = mk_anon (ref (AbstractStatics a)) in - {(mk_typedef a.a_module path a.a_pos null_pos t) with t_private = true} +let mk_abstract m path pos name_pos = + { + a_path = path; + a_private = false; + a_module = m; + a_pos = pos; + a_name_pos = name_pos; + a_doc = None; + a_params = []; + a_using = []; + a_restore = (fun () -> ()); + a_meta = []; + a_from = []; + a_to = []; + a_from_field = []; + a_to_field = []; + a_ops = []; + a_unops = []; + a_impl = None; + a_array = []; + a_this = mk_mono(); + a_read = None; + a_write = None; + a_enum = false; + a_call = None; + } module TClass = struct let get_member_fields' self_too c0 tl = diff --git a/src/core/texpr.ml b/src/core/texpr.ml index 433e5ddf654..848c1bebc1c 100644 --- a/src/core/texpr.ml +++ b/src/core/texpr.ml @@ -486,15 +486,14 @@ let foldmap f acc e = (* Collection of functions that return expressions *) module Builder = struct let make_static_this c p = - let ta = mk_anon ~fields:c.cl_statics (ref (ClassStatics c)) in - mk (TTypeExpr (TClassDecl c)) ta p + mk (TTypeExpr (TClassDecl c)) (TType(TFunctions.class_module_type c,[])) p let make_typeexpr mt pos = let t = match resolve_typedef mt with - | TClassDecl c -> mk_anon ~fields:c.cl_statics (ref (ClassStatics c)) - | TEnumDecl e -> mk_anon (ref (EnumStatics e)) - | TAbstractDecl a -> mk_anon (ref (AbstractStatics a)) + | TClassDecl c -> TType(class_module_type c,[]) + | TEnumDecl e -> TType(e.e_type,[]) + | TAbstractDecl a -> TType(abstract_module_type a [],[]) | _ -> die "" __LOC__ in mk (TTypeExpr mt) t pos diff --git a/src/generators/genpy.ml b/src/generators/genpy.ml index 715c8b8d262..3e42aa58628 100644 --- a/src/generators/genpy.ml +++ b/src/generators/genpy.ml @@ -38,8 +38,7 @@ module Utils = struct abort (Printf.sprintf "Could not find type %s\n" (s_type_path path)) null_pos let mk_static_field c cf p = - let ta = mk_anon ~fields:c.cl_statics (ref (ClassStatics c)) in - let ethis = mk (TTypeExpr (TClassDecl c)) ta p in + let ethis = Texpr.Builder.make_static_this c p in let t = monomorphs cf.cf_params cf.cf_type in mk (TField (ethis,(FStatic (c,cf)))) t p diff --git a/src/optimization/inline.ml b/src/optimization/inline.ml index a51f6a1d8b4..a9709f37040 100644 --- a/src/optimization/inline.ml +++ b/src/optimization/inline.ml @@ -113,7 +113,7 @@ let api_inline ctx c field params p = let m = (try ctx.com.module_lut#find path with Not_found -> die "" __LOC__) in add_dependency ctx.m.curmod m; Option.get (ExtList.List.find_map (function - | TClassDecl cl when cl.cl_path = path -> Some (make_static_this cl p) + | TClassDecl cl when cl.cl_path = path -> Some (Texpr.Builder.make_static_this cl p) | _ -> None ) m.m_types) in @@ -173,7 +173,7 @@ let api_inline ctx c field params p = None) | (["js"],"Boot"),"__downcastCheck",[o; {eexpr = TTypeExpr (TClassDecl cls) } as t] when ctx.com.platform = Js -> if (has_class_flag cls CInterface) then - Some (Texpr.Builder.fcall (make_static_this c p) "__implements" [o;t] tbool p) + Some (Texpr.Builder.fcall (Texpr.Builder.make_static_this c p) "__implements" [o;t] tbool p) else Some (Texpr.Builder.fcall (eJsSyntax()) "instanceof" [o;t] tbool p) | (["cs" | "java"],"Lib"),("nativeArray"),[{ eexpr = TArrayDecl args } as edecl; _] diff --git a/src/typing/finalization.ml b/src/typing/finalization.ml index 92a02d7303e..1cba3d378fc 100644 --- a/src/typing/finalization.ml +++ b/src/typing/finalization.ml @@ -49,7 +49,7 @@ let get_main ctx types = let et = List.find (fun t -> t_path t = path) types in let ec = (match et with TClassDecl c -> c | _ -> die "" __LOC__) in let ef = PMap.find method_name ec.cl_statics in - let et = mk (TTypeExpr et) (mk_anon (ref (ClassStatics ec))) null_pos in + let et = Texpr.Builder.make_typeexpr et null_pos in mk (TCall (mk (TField (et,FStatic (ec,ef))) ef.cf_type null_pos,[])) ctx.t.tvoid null_pos in (* add haxe.EntryPoint.run() call *) diff --git a/src/typing/tanon_identification.ml b/src/typing/tanon_identification.ml index 4e76f5c4152..4a57293cf93 100644 --- a/src/typing/tanon_identification.ml +++ b/src/typing/tanon_identification.ml @@ -145,9 +145,13 @@ object(self) } in match !(an.a_status) with | ClassStatics {cl_path = path} | EnumStatics {e_path = path} | AbstractStatics {a_path = path} -> - let pfm = make_pfm path in - self#add_pfm path pfm; - Some pfm + begin try + Some (Hashtbl.find pfms path) + with Not_found -> + let pfm = make_pfm path in + self#add_pfm path pfm; + Some pfm + end | _ -> let arity = PMap.fold (fun cf i -> replace_mono cf.cf_type; From f1b7c7c1bb27d67fe7b11854717f4200cb57918b Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 27 Dec 2023 20:28:06 +0100 Subject: [PATCH 044/184] [typer] handle e_type like a human being would --- src/core/tFunctions.ml | 8 ++++---- src/core/tOther.ml | 2 +- src/core/tPrinting.ml | 2 +- src/core/tType.ml | 2 +- src/core/texpr.ml | 2 +- src/typing/typeloadModule.ml | 14 ++------------ src/typing/typerBase.ml | 3 +-- 7 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index cea0faabb0c..ae2c980a69d 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -884,10 +884,10 @@ let class_module_type c = let t = mk_anon ~fields:c.cl_statics (ref (ClassStatics c)) in { (mk_typedef c.cl_module path c.cl_pos null_pos t) with t_private = true} -let enum_module_type m path p = - let path = ([], "Enum<" ^ (s_type_path path) ^ ">") in - let t = mk_mono() in - {(mk_typedef m path p null_pos t) with t_private = true} +let enum_module_type en fields = + let path = ([], "Enum<" ^ (s_type_path en.e_path) ^ ">") in + let t = mk_anon ~fields (ref (EnumStatics en)) in + {(mk_typedef en.e_module path en.e_pos null_pos t) with t_private = true} let abstract_module_type a tl = let path = ([],Printf.sprintf "Abstract<%s>" (s_type_path a.a_path)) in diff --git a/src/core/tOther.ml b/src/core/tOther.ml index 2366b731a9a..8c0a11e469b 100644 --- a/src/core/tOther.ml +++ b/src/core/tOther.ml @@ -278,7 +278,7 @@ let mk_enum m path pos name_pos = e_extern = false; e_constrs = PMap.empty; e_names = []; - e_type = enum_module_type m path pos; + e_type = mk_mono(); } let mk_abstract m path pos name_pos = diff --git a/src/core/tPrinting.ml b/src/core/tPrinting.ml index 0757e7cda56..ea3a44a988f 100644 --- a/src/core/tPrinting.ml +++ b/src/core/tPrinting.ml @@ -528,7 +528,7 @@ module Printer = struct "d_doc",s_doc en.e_doc; "e_meta",s_metadata en.e_meta; "e_params",s_type_params en.e_params; - "e_type",s_tdef "\t" en.e_type; + "e_type",s_type_kind en.e_type; "e_extern",string_of_bool en.e_extern; "e_constrs",s_list "\n\t" (s_tenum_field (tabs ^ "\t")) (PMap.fold (fun ef acc -> ef :: acc) en.e_constrs []); "e_names",String.concat ", " en.e_names diff --git a/src/core/tType.ml b/src/core/tType.ml index 2a5e8fb2723..2a78187d734 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -314,7 +314,7 @@ and tenum = { mutable e_using : (tclass * pos) list; mutable e_restore : unit -> unit; (* do not insert any fields above *) - e_type : tdef; + e_type : t; mutable e_extern : bool; mutable e_constrs : (string , tenum_field) PMap.t; mutable e_names : string list; diff --git a/src/core/texpr.ml b/src/core/texpr.ml index 848c1bebc1c..3082e210b04 100644 --- a/src/core/texpr.ml +++ b/src/core/texpr.ml @@ -492,7 +492,7 @@ module Builder = struct let t = match resolve_typedef mt with | TClassDecl c -> TType(class_module_type c,[]) - | TEnumDecl e -> TType(e.e_type,[]) + | TEnumDecl e -> e.e_type | TAbstractDecl a -> TType(abstract_module_type a [],[]) | _ -> die "" __LOC__ in diff --git a/src/typing/typeloadModule.ml b/src/typing/typeloadModule.ml index 4a10021b50c..41d1738ce50 100644 --- a/src/typing/typeloadModule.ml +++ b/src/typing/typeloadModule.ml @@ -132,20 +132,11 @@ module ModuleLevel = struct let path = make_path name priv d.d_meta p in if Meta.has (Meta.Custom ":fakeEnum") d.d_meta then raise_typing_error "@:fakeEnum enums is no longer supported in Haxe 4, use extern enum abstract instead" p; let e = { - e_path = path; - e_module = m; - e_pos = p; - e_name_pos = (pos d.d_name); + (mk_enum m path p (pos d.d_name)) with e_doc = d.d_doc; e_meta = d.d_meta; - e_params = []; - e_using = []; - e_restore = (fun () -> ()); e_private = priv; e_extern = List.mem EExtern d.d_flags; - e_constrs = PMap.empty; - e_names = []; - e_type = enum_module_type m path p; } in if not e.e_extern then check_type_name name d.d_meta; decls := (TEnumDecl e, decl) :: !decls; @@ -535,8 +526,7 @@ module TypeLevel = struct ) (!constructs); e.e_names <- List.rev !names; e.e_extern <- e.e_extern; - e.e_type.t_params <- e.e_params; - e.e_type.t_type <- mk_anon ~fields:!fields (ref (EnumStatics e)); + unify ctx (TType(enum_module_type e !fields,[])) e.e_type p; if !is_flat then e.e_meta <- (Meta.FlatEnum,[],null_pos) :: e.e_meta; if Meta.has Meta.InheritDoc e.e_meta then delay ctx PConnectField (fun() -> InheritDoc.build_enum_doc ctx e); diff --git a/src/typing/typerBase.ml b/src/typing/typerBase.ml index b03fce5ebe2..ddfbb114991 100644 --- a/src/typing/typerBase.ml +++ b/src/typing/typerBase.ml @@ -210,8 +210,7 @@ let type_module_type ctx t p = let t_tmp = class_module_type c in mk (TTypeExpr (TClassDecl c)) (TType (t_tmp,[])) p | TEnumDecl e -> - let types = (match tparams with None -> Monomorph.spawn_constrained_monos (fun t -> t) e.e_params | Some l -> l) in - mk (TTypeExpr (TEnumDecl e)) (TType (e.e_type,types)) p + mk (TTypeExpr (TEnumDecl e)) e.e_type p | TTypeDecl s -> let t = apply_typedef s (List.map (fun _ -> spawn_monomorph ctx p) s.t_params) in DeprecationCheck.check_typedef (create_deprecation_context ctx) s p; From 798e0c0000402fdcc3956388ef0d0fa2908787b7 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 28 Dec 2023 09:00:51 +0100 Subject: [PATCH 045/184] [typer] don't die so hard if we cannot locate the length field for iteration This can happen in some display situations when the type is incomplete. --- src/typing/forLoop.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typing/forLoop.ml b/src/typing/forLoop.ml index a14f796c81b..65b67979cd5 100644 --- a/src/typing/forLoop.ml +++ b/src/typing/forLoop.ml @@ -267,7 +267,7 @@ module IterationKind = struct let t_void = ctx.t.tvoid in let t_int = ctx.t.tint in let mk_field e n = - TField (e,try quick_field e.etype n with Not_found -> die "" __LOC__) + TField (e,try quick_field e.etype n with Not_found -> Error.raise_msg (Printf.sprintf "Could not find field %s on %s" n (s_type_kind e.etype)) e.epos) in let get_array_length arr p = mk (mk_field arr "length") ctx.com.basic.tint p From d847c9c76b068513f05baf5cd0ad7cfc09806f3c Mon Sep 17 00:00:00 2001 From: Zorbn <70043176+Zorbn@users.noreply.github.com> Date: Thu, 28 Dec 2023 00:22:08 -0800 Subject: [PATCH 046/184] [lua] Fix unnecessary _hx_do_first (#11453) --- src/generators/genlua.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/generators/genlua.ml b/src/generators/genlua.ml index 3bbd314104e..4dda9564ddd 100644 --- a/src/generators/genlua.ml +++ b/src/generators/genlua.ml @@ -582,9 +582,10 @@ and gen_loop ctx cond do_while e = if do_while then print ctx " or _hx_do_first_%i" ctx.break_depth; print ctx " do "; - if do_while then + if do_while then begin newline ctx; println ctx "_hx_do_first_%i = false;" ctx.break_depth; + end; if will_continue then print ctx "repeat "; gen_block_element ctx e; if will_continue then begin From 0ee63b352e8c3eea063dac51790b9137edb5d83b Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 28 Dec 2023 10:01:40 +0100 Subject: [PATCH 047/184] [typer] merge module_lut and type_to_module --- src/compiler/displayProcessing.ml | 4 ++-- src/context/common.ml | 20 ++++++++++++++------ src/filters/filters.ml | 2 +- src/optimization/dce.ml | 3 +-- src/typing/finalization.ml | 2 +- src/typing/generic.ml | 4 ++-- src/typing/macroContext.ml | 2 +- src/typing/typeloadCheck.ml | 4 ++-- src/typing/typeloadFields.ml | 2 +- 9 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/compiler/displayProcessing.ml b/src/compiler/displayProcessing.ml index 70c217d91fe..8bfc95efab8 100644 --- a/src/compiler/displayProcessing.ml +++ b/src/compiler/displayProcessing.ml @@ -200,11 +200,11 @@ let load_display_module_in_macro tctx display_file_dot_path clear = match displa begin try let m = mctx.com.module_lut#find cpath in mctx.com.module_lut#remove cpath; - mctx.com.type_to_module#remove cpath; + mctx.com.module_lut#get_type_lut#remove cpath; List.iter (fun mt -> let ti = Type.t_infos mt in mctx.com.module_lut#remove ti.mt_path; - mctx.com.type_to_module#remove ti.mt_path; + mctx.com.module_lut#get_type_lut#remove ti.mt_path; ) m.m_types with Not_found -> () diff --git a/src/context/common.ml b/src/context/common.ml index 401e51e974f..a856808dbed 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -355,6 +355,17 @@ class ['key,'value] hashtbl_lookup = object(self) Hashtbl.clear lut end +class module_lut = object(self) + inherit [path,module_def] hashtbl_lookup as super + + val type_lut : (path,path) lookup = new hashtbl_lookup + + method find_by_type (path : path) = + self#find (type_lut#find path) + + method get_type_lut = type_lut +end + type context = { compilation_step : int; mutable stage : compiler_stage; @@ -408,9 +419,8 @@ type context = { cached_macros : (path * string,(((string * bool * t) list * t * tclass * Type.tclass_field) * module_def)) lookup; stored_typed_exprs : (int, texpr) lookup; overload_cache : ((path * string),(Type.t * tclass_field) list) lookup; - module_lut : (path,module_def) lookup; + module_lut : module_lut; module_nonexistent_lut : (path,bool) lookup; - type_to_module : (path,path) lookup; mutable has_error : bool; pass_debug_messages : string DynArray.t; (* output *) @@ -837,9 +847,8 @@ let create compilation_step cs version args display_mode = callbacks = new compiler_callbacks; global_metadata = []; modules = []; - module_lut = new hashtbl_lookup; + module_lut = new module_lut; module_nonexistent_lut = new hashtbl_lookup; - type_to_module = new hashtbl_lookup; main = None; flash_version = 10.; resources = Hashtbl.create 0; @@ -928,8 +937,7 @@ let clone com is_macro_context = parser_cache = new hashtbl_lookup; module_to_file = new hashtbl_lookup; overload_cache = new hashtbl_lookup; - module_lut = new hashtbl_lookup; - type_to_module = new hashtbl_lookup; + module_lut = new module_lut; } let file_time file = Extc.filetime file diff --git a/src/filters/filters.ml b/src/filters/filters.ml index e3ab6478d7c..0ee097c09ae 100644 --- a/src/filters/filters.ml +++ b/src/filters/filters.ml @@ -323,7 +323,7 @@ let remove_extern_fields com t = match t with let check_private_path com t = match t with | TClassDecl c when c.cl_private -> let rpath = (fst c.cl_module.m_path,"_" ^ snd c.cl_module.m_path) in - if com.type_to_module#mem rpath then raise_typing_error ("This private class name will clash with " ^ s_type_path rpath) c.cl_pos; + if com.module_lut#get_type_lut#mem rpath then raise_typing_error ("This private class name will clash with " ^ s_type_path rpath) c.cl_pos; | _ -> () diff --git a/src/optimization/dce.ml b/src/optimization/dce.ml index 96c198cd7e0..0d1a4970899 100644 --- a/src/optimization/dce.ml +++ b/src/optimization/dce.ml @@ -61,8 +61,7 @@ let find_field c name kind = let resolve_class_field_ref ctx cfr = let ctx = if cfr.cfr_is_macro && not ctx.is_macro_context then Option.get (ctx.get_macros()) else ctx in - let path = ctx.type_to_module#find cfr.cfr_path in - let m = ctx.module_lut#find path in + let m = ctx.module_lut#find_by_type cfr.cfr_path in Option.get (ExtList.List.find_map (fun mt -> match mt with | TClassDecl c when c.cl_path = cfr.cfr_path -> diff --git a/src/typing/finalization.ml b/src/typing/finalization.ml index 1cba3d378fc..806cfd678b8 100644 --- a/src/typing/finalization.ml +++ b/src/typing/finalization.ml @@ -101,7 +101,7 @@ type state = | Done | NotYet -let sort_types com (modules : (path,module_def) lookup) = +let sort_types com (modules : module_lut) = let types = ref [] in let states = Hashtbl.create 0 in let state p = try Hashtbl.find states p with Not_found -> NotYet in diff --git a/src/typing/generic.ml b/src/typing/generic.ml index c9dcf4d3713..dda73fc982d 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -175,7 +175,7 @@ let static_method_container gctx c cf p = | TInst(cg,_) -> cg | _ -> raise_typing_error ("Cannot specialize @:generic static method because the generated type name is already used: " ^ name) p with Error { err_message = Module_not_found path } when path = (pack,name) -> - let m = (try ctx.com.module_lut#find (ctx.com.type_to_module#find c.cl_path) with Not_found -> die "" __LOC__) in + let m = c.cl_module in let mg = { m_id = alloc_mid(); m_path = (pack,name); @@ -261,7 +261,7 @@ let build_generic_class ctx c p tl = | TInst({ cl_kind = KGenericInstance (csup,_) },_) when c == csup -> t | _ -> raise_typing_error ("Cannot specialize @:generic because the generated type name is already used: " ^ name) p with Error { err_message = Module_not_found path } when path = (pack,name) -> - let m = (try ctx.com.module_lut#find (ctx.com.type_to_module#find c.cl_path) with Not_found -> die "" __LOC__) in + let m = c.cl_module in if gctx.generic_debug then begin print_endline (Printf.sprintf "[GENERIC] Building @:generic class %s as %s with:" (s_type_path c.cl_path) name); List.iter (fun (t1,(t2,eo)) -> diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index 96a3c07e5ff..d5df49e80bb 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -739,7 +739,7 @@ let get_macro_context ctx = mctx let load_macro_module mctx com cpath display p = - let m = (try com.type_to_module#find cpath with Not_found -> cpath) in + let m = (try com.module_lut#get_type_lut#find cpath with Not_found -> cpath) in (* Temporarily enter display mode while typing the macro. *) let old = mctx.com.display in if display then mctx.com.display <- com.display; diff --git a/src/typing/typeloadCheck.ml b/src/typing/typeloadCheck.ml index e343c1414e2..d9189bb0519 100644 --- a/src/typing/typeloadCheck.ml +++ b/src/typing/typeloadCheck.ml @@ -337,7 +337,7 @@ let check_global_metadata ctx meta f_add mpath tpath so = 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 + let path2 = ctx.com.module_lut#get_type_lut#find t.mt_path in 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 @@ -346,7 +346,7 @@ let check_module_types ctx m p t = raise_typing_error (Printf.sprintf "Type name %s is redefined from module %s (%s)" (s_type_path t.mt_path) (s_type_path path2) s) p with Not_found -> - ctx.com.type_to_module#add t.mt_path m.m_path + ctx.com.module_lut#get_type_lut#add t.mt_path m.m_path module Inheritance = struct let is_basic_class_path path = match path with diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index a0536851016..a34edc6c3e9 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -697,7 +697,7 @@ let transform_field (ctx,cctx) c f fields p = in if List.mem_assoc AMacro f.cff_access then (match ctx.g.macros with - | Some (_,mctx) when mctx.com.type_to_module#mem c.cl_path -> + | Some (_,mctx) when mctx.com.module_lut#get_type_lut#mem c.cl_path -> (* assume that if we had already a macro with the same name, it has not been changed during the @:build operation *) if not (List.exists (fun f2 -> f2.cff_name = f.cff_name && List.mem_assoc AMacro f2.cff_access) (!fields)) then raise_typing_error "Class build macro cannot return a macro function when the class has already been compiled into the macro context" p From a7df996294f0ac983dc600b0c8c74819ddea66c7 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 28 Dec 2023 12:57:31 +0100 Subject: [PATCH 048/184] pull some auxiliary changes from hxb branch --- src/compiler/serverCompilationContext.ml | 4 +- src/context/common.ml | 92 ++++++----------- src/context/feature.ml | 11 ++ src/context/lookup.ml | 113 +++++++++++++++++++++ src/context/typecore.ml | 1 + src/core/displayTypes.ml | 2 +- src/core/naming.ml | 4 +- src/core/tFunctions.ml | 65 ++++++++++-- src/core/tOther.ml | 48 ++++++++- src/core/tPrinting.ml | 2 +- src/core/tType.ml | 22 ++-- src/filters/localStatic.ml | 3 +- src/typing/finalization.ml | 1 + src/typing/matcher/exprToPattern.ml | 2 +- src/typing/typeload.ml | 2 +- src/typing/typeloadCheck.ml | 14 --- src/typing/typeloadFields.ml | 16 ++- src/typing/typeloadModule.ml | 16 +-- src/typing/typer.ml | 2 +- src/typing/typerEntry.ml | 6 +- tests/server/src/Main.hx | 2 +- tests/server/src/cases/issues/Issue9690.hx | 2 +- 22 files changed, 297 insertions(+), 133 deletions(-) create mode 100644 src/context/feature.ml create mode 100644 src/context/lookup.ml diff --git a/src/compiler/serverCompilationContext.ml b/src/compiler/serverCompilationContext.ml index 0f65f22c154..d0c87099acd 100644 --- a/src/compiler/serverCompilationContext.ml +++ b/src/compiler/serverCompilationContext.ml @@ -72,7 +72,7 @@ let ensure_macro_setup sctx = let cleanup () = match !MacroContext.macro_interp_cache with | Some interp -> (* curapi holds a reference to the typing context which we don't want to persist. Let's unset it so the - context can be collected. *) + context can be collected. *) interp.curapi <- Obj.magic "" | None -> - () \ No newline at end of file + () diff --git a/src/context/common.ml b/src/context/common.ml index a856808dbed..6fbfba69569 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -20,6 +20,7 @@ open Extlib_leftovers open Ast open Type open Globals +open Lookup open Define open NativeLibraries open Warning @@ -293,76 +294,43 @@ type report_mode = | RMDiagnostics of (Path.UniqueKey.t list) | RMStatistics -class virtual ['key,'value] lookup = object(self) - method virtual add : 'key -> 'value -> unit - method virtual remove : 'key -> unit - method virtual find : 'key -> 'value - method virtual iter : ('key -> 'value -> unit) -> unit - method virtual fold : 'acc . ('key -> 'value -> 'acc -> 'acc) -> 'acc -> 'acc - method virtual mem : 'key -> bool - method virtual clear : unit -end - -class ['key,'value] pmap_lookup = object(self) - inherit ['key,'value] lookup - val mutable lut : ('key,'value) PMap.t = PMap.empty - - method add (key : 'key) (value : 'value) = - lut <- PMap.add key value lut - - method remove (key : 'key) = - lut <- PMap.remove key lut - - method find (key : 'key) : 'value = - PMap.find key lut - - method iter (f : 'key -> 'value -> unit) = - PMap.iter f lut - - method fold : 'acc . ('key -> 'value -> 'acc -> 'acc) -> 'acc -> 'acc = fun f acc -> - PMap.foldi f lut acc - - method mem (key : 'key) = - PMap.mem key lut - - method clear = - lut <- PMap.empty -end - -class ['key,'value] hashtbl_lookup = object(self) - inherit ['key,'value] lookup - val lut : ('key,'value) Hashtbl.t = Hashtbl.create 0 - - method add (key : 'key) (value : 'value) = - Hashtbl.replace lut key value - - method remove (key : 'key) = - Hashtbl.remove lut key - - method find (key : 'key) : 'value = - Hashtbl.find lut key - - method iter (f : 'key -> 'value -> unit) = - Hashtbl.iter f lut - - method fold : 'acc . ('key -> 'value -> 'acc -> 'acc) -> 'acc -> 'acc = fun f acc -> - Hashtbl.fold f lut acc - - method mem (key : 'key) = - Hashtbl.mem lut key - - method clear = - Hashtbl.clear lut -end - class module_lut = object(self) inherit [path,module_def] hashtbl_lookup as super val type_lut : (path,path) lookup = new hashtbl_lookup + method add_module_type (m : module_def) (mt : module_type) = + let t = t_infos mt in + try + let path2 = type_lut#find t.mt_path in + let p = t.mt_pos in + if m.m_path <> path2 && String.lowercase_ascii (s_type_path path2) = String.lowercase_ascii (s_type_path m.m_path) then Error.raise_typing_error ("Module " ^ s_type_path path2 ^ " is loaded with a different case than " ^ s_type_path m.m_path) p; + let m2 = self#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 + let s = if hex1 = hex2 then hex1 else Printf.sprintf "was %s, is %s" hex2 hex1 in + Error.raise_typing_error (Printf.sprintf "Type name %s is redefined from module %s (%s)" (s_type_path t.mt_path) (s_type_path path2) s) p + with Not_found -> + type_lut#add t.mt_path m.m_path + + method add (path : path) (m : module_def) = + super#add path m; + List.iter (fun mt -> self#add_module_type m mt) m.m_types + + method remove (path : path) = + try + List.iter (fun mt -> type_lut#remove (t_path mt)) (self#find path).m_types; + super#remove path; + with Not_found -> + () + method find_by_type (path : path) = self#find (type_lut#find path) + method clear = + super#clear; + type_lut#clear + method get_type_lut = type_lut end diff --git a/src/context/feature.ml b/src/context/feature.ml new file mode 100644 index 00000000000..647d03da10b --- /dev/null +++ b/src/context/feature.ml @@ -0,0 +1,11 @@ +open Ast +open Type +open Error + +let rec check_if_feature = function + | [] -> [] + | (Meta.IfFeature,el,_) :: _ -> List.map (fun (e,p) -> match e with EConst (String(s,_)) -> s | _ -> raise_typing_error "String expected" p) el + | _ :: l -> check_if_feature l + +let set_feature m cf_ref s = + m.m_extra.m_if_feature <- (s, cf_ref) :: m.m_extra.m_if_feature diff --git a/src/context/lookup.ml b/src/context/lookup.ml new file mode 100644 index 00000000000..73b639c1597 --- /dev/null +++ b/src/context/lookup.ml @@ -0,0 +1,113 @@ + +class virtual ['key,'value] lookup = object(self) + method virtual add : 'key -> 'value -> unit + method virtual remove : 'key -> unit + method virtual find : 'key -> 'value + method virtual iter : ('key -> 'value -> unit) -> unit + method virtual fold : 'acc . ('key -> 'value -> 'acc -> 'acc) -> 'acc -> 'acc + method virtual mem : 'key -> bool + method virtual clear : unit + + method virtual start_group : int + method virtual commit_group : int -> int + method virtual discard_group : int -> int +end + +class ['key,'value] pmap_lookup = object(self) + inherit ['key,'value] lookup + val mutable lut : ('key,'value) PMap.t = PMap.empty + + val mutable group_id : int ref = ref 0 + val mutable groups : (int,'key list) PMap.t = PMap.empty + + method add (key : 'key) (value : 'value) = + groups <- PMap.map (fun modules -> key :: modules) groups; + lut <- PMap.add key value lut + + method remove (key : 'key) = + lut <- PMap.remove key lut + + method find (key : 'key) : 'value = + PMap.find key lut + + method iter (f : 'key -> 'value -> unit) = + PMap.iter f lut + + method fold : 'acc . ('key -> 'value -> 'acc -> 'acc) -> 'acc -> 'acc = fun f acc -> + PMap.foldi f lut acc + + method mem (key : 'key) = + PMap.mem key lut + + method clear = + lut <- PMap.empty + + method start_group = + incr group_id; + let i = !group_id in + groups <- PMap.add i [] groups; + i + + method commit_group i = + let group = PMap.find i groups in + let n = List.length group in + groups <- PMap.remove i groups; + n + + method discard_group i = + let group = PMap.find i groups in + let n = List.length group in + List.iter (fun mpath -> self#remove mpath) group; + groups <- PMap.remove i groups; + n +end + +class ['key,'value] hashtbl_lookup = object(self) + inherit ['key,'value] lookup + val lut : ('key,'value) Hashtbl.t = Hashtbl.create 0 + + val mutable group_id : int ref = ref 0 + val mutable groups : (int,'key list) Hashtbl.t = Hashtbl.create 0 + + method add (key : 'key) (value : 'value) = + Hashtbl.iter (fun i modules -> Hashtbl.replace groups i (key :: modules)) groups; + Hashtbl.replace lut key value + + method remove (key : 'key) = + Hashtbl.remove lut key + + method find (key : 'key) : 'value = + Hashtbl.find lut key + + method iter (f : 'key -> 'value -> unit) = + Hashtbl.iter f lut + + method fold : 'acc . ('key -> 'value -> 'acc -> 'acc) -> 'acc -> 'acc = fun f acc -> + Hashtbl.fold f lut acc + + method mem (key : 'key) = + Hashtbl.mem lut key + + method clear = + Hashtbl.clear lut + + method start_group = + incr group_id; + let i = !group_id in + Hashtbl.replace groups i []; + i + + method commit_group i = + let group = Hashtbl.find groups i in + let n = List.length group in + Hashtbl.remove groups i; + n + + method discard_group i = + let group = Hashtbl.find groups i in + let n = List.length group in + List.iter (fun mpath -> self#remove mpath) group; + Hashtbl.remove groups i; + n +end + diff --git a/src/context/typecore.ml b/src/context/typecore.ml index 56769dad5c6..87904211ae5 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -20,6 +20,7 @@ open Globals open Ast open Common +open Lookup open Type open Error open Resolution diff --git a/src/core/displayTypes.ml b/src/core/displayTypes.ml index b9bacf7f75e..5d8f0c3b706 100644 --- a/src/core/displayTypes.ml +++ b/src/core/displayTypes.ml @@ -352,4 +352,4 @@ type display_exception_kind = | DisplayPositions of pos list | DisplayFields of fields_result | DisplayPackage of string list - | DisplayNoResult \ No newline at end of file + | DisplayNoResult diff --git a/src/core/naming.ml b/src/core/naming.ml index 05b9bedb4ef..2a3b3641768 100644 --- a/src/core/naming.ml +++ b/src/core/naming.ml @@ -1,8 +1,6 @@ open Globals open Ast -open Meta open Type -open Error (** retrieve string from @:native metadata or raise Not_found *) let get_native_name meta = @@ -85,4 +83,4 @@ let apply_native_paths t = | _ -> ()) with Not_found -> - () \ No newline at end of file + () diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index ae2c980a69d..12913bafa59 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -199,19 +199,53 @@ let mk_field name ?(public = true) ?(static = false) t p name_pos = { } let null_module = { - m_id = alloc_mid(); - m_path = [] , ""; - m_types = []; - m_statics = None; - m_extra = module_extra "" "" 0. MFake []; - } + m_id = alloc_mid(); + m_path = [] , ""; + m_types = []; + m_statics = None; + m_extra = module_extra "" "" 0. MFake []; +} let null_class = let c = mk_class null_module ([],"") null_pos null_pos in c.cl_private <- true; c +let null_typedef = + let t = mk_typedef null_module ([],"") null_pos null_pos (TDynamic None) in + t.t_private <- true; + t + +let null_tanon = { a_fields = PMap.empty; a_status = ref Closed } + +let null_enum = { + e_path = ([],""); + e_module = null_module; + e_pos = null_pos; + e_name_pos = null_pos; + e_private = true; + e_doc = None; + e_meta = []; + e_params = []; + e_using = []; + e_restore = (fun () -> ()); + e_type = t_dynamic; + e_extern = false; + e_constrs = PMap.empty; + e_names = []; +} + let null_field = mk_field "" t_dynamic null_pos null_pos +let null_enum_field = { + ef_name = ""; + ef_type = TEnum (null_enum, []); + ef_pos = null_pos; + ef_name_pos = null_pos; + ef_doc = None; + ef_index = 0; + ef_params = []; + ef_meta = []; +} let null_abstract = { a_path = ([],""); @@ -518,6 +552,15 @@ let rec follow t = follow t | _ -> t +let rec follow_lazy t = + match t with + | TLazy f -> + (match !f with + | LAvailable t -> follow_lazy t + | _ -> follow_lazy (lazy_type f) + ) + | _ -> t + let follow_once t = match t with | TMono r -> @@ -893,3 +936,13 @@ let abstract_module_type a tl = let path = ([],Printf.sprintf "Abstract<%s>" (s_type_path a.a_path)) in let t = mk_anon (ref (AbstractStatics a)) in {(mk_typedef a.a_module path a.a_pos null_pos t) with t_private = true} + +let class_field_of_enum_field ef = { + (mk_field ef.ef_name ef.ef_type ef.ef_pos ef.ef_name_pos) with + cf_kind = (match follow ef.ef_type with + | TFun _ -> Method MethNormal + | _ -> Var { v_read = AccNormal; v_write = AccNo } + ); + cf_doc = ef.ef_doc; + cf_params = ef.ef_params; +} \ No newline at end of file diff --git a/src/core/tOther.ml b/src/core/tOther.ml index 8c0a11e469b..71bad6921ee 100644 --- a/src/core/tOther.ml +++ b/src/core/tOther.ml @@ -2,7 +2,6 @@ open Globals open Ast open TType open TFunctions -open TPrinting module TExprToExpr = struct let tpath path module_path params = @@ -263,6 +262,51 @@ end let no_meta = [] +let mk_enum m path pos name_pos = + { + e_path = path; + e_module = m; + e_pos = pos; + e_name_pos = name_pos; + e_doc = None; + e_meta = []; + e_params = []; + e_using = []; + e_restore = (fun () -> ()); + e_private = false; + e_extern = false; + e_constrs = PMap.empty; + e_names = []; + e_type = mk_mono(); + } + +let mk_abstract m path pos name_pos = + { + a_path = path; + a_private = false; + a_module = m; + a_pos = pos; + a_name_pos = name_pos; + a_doc = None; + a_params = []; + a_using = []; + a_restore = (fun () -> ()); + a_meta = []; + a_from = []; + a_to = []; + a_from_field = []; + a_to_field = []; + a_ops = []; + a_unops = []; + a_impl = None; + a_array = []; + a_this = mk_mono(); + a_read = None; + a_write = None; + a_enum = false; + a_call = None; + } + let mk_enum m path pos name_pos = { e_path = path; @@ -375,4 +419,4 @@ let s_class_path c = | KAbstractImpl a -> a.a_path | _ -> c.cl_path in - s_type_path path \ No newline at end of file + s_type_path path diff --git a/src/core/tPrinting.ml b/src/core/tPrinting.ml index ea3a44a988f..4a3e1522ca8 100644 --- a/src/core/tPrinting.ml +++ b/src/core/tPrinting.ml @@ -441,7 +441,7 @@ module Printer = struct let s_metadata metadata = s_list " " s_metadata_entry metadata - let s_type_param ttp = + let s_type_param ttp = let s = match (get_constraints ttp) with | [] -> ttp.ttp_name | tl1 -> Printf.sprintf "%s:%s" ttp.ttp_name (String.concat " & " (List.map s_type tl1)) diff --git a/src/core/tType.ml b/src/core/tType.ml index 2a78187d734..0cd1e2c8d27 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -92,10 +92,10 @@ and tparams = t list and typed_type_param = { ttp_name : string; - ttp_type : t; ttp_class : tclass; + mutable ttp_type : t; mutable ttp_constraints : t list Lazy.t option; - ttp_default : t option; + mutable ttp_default : t option; } and type_params = typed_type_param list @@ -250,10 +250,10 @@ and tinfos = { mt_module : module_def; mt_pos : pos; mt_name_pos : pos; - mt_private : bool; - mt_doc : Ast.documentation; + mutable mt_private : bool; + mutable mt_doc : Ast.documentation; mutable mt_meta : metadata; - mt_params : type_params; + mutable mt_params : type_params; mutable mt_using : (tclass * pos) list; mutable mt_restore : unit -> unit; } @@ -307,14 +307,14 @@ and tenum = { e_module : module_def; e_pos : pos; e_name_pos : pos; - e_private : bool; + mutable e_private : bool; mutable e_doc : Ast.documentation; mutable e_meta : metadata; mutable e_params : type_params; mutable e_using : (tclass * pos) list; mutable e_restore : unit -> unit; (* do not insert any fields above *) - e_type : t; + mutable e_type : t; mutable e_extern : bool; mutable e_constrs : (string , tenum_field) PMap.t; mutable e_names : string list; @@ -325,8 +325,8 @@ and tdef = { t_module : module_def; t_pos : pos; t_name_pos : pos; - t_private : bool; - t_doc : Ast.documentation; + mutable t_private : bool; + mutable t_doc : Ast.documentation; mutable t_meta : metadata; mutable t_params : type_params; mutable t_using : (tclass * pos) list; @@ -340,7 +340,7 @@ and tabstract = { a_module : module_def; a_pos : pos; a_name_pos : pos; - a_private : bool; + mutable a_private : bool; mutable a_doc : Ast.documentation; mutable a_meta : metadata; mutable a_params : type_params; @@ -359,7 +359,7 @@ and tabstract = { mutable a_read : tclass_field option; mutable a_write : tclass_field option; mutable a_call : tclass_field option; - a_enum : bool; + mutable a_enum : bool; } and module_type = diff --git a/src/filters/localStatic.ml b/src/filters/localStatic.ml index ce1f5dbaf9b..50b5d759c8d 100644 --- a/src/filters/localStatic.ml +++ b/src/filters/localStatic.ml @@ -1,4 +1,3 @@ -open Global open Common open Type open Typecore @@ -60,4 +59,4 @@ let run ctx e = | _ -> Type.map_expr run e in - run e \ No newline at end of file + run e diff --git a/src/typing/finalization.ml b/src/typing/finalization.ml index 806cfd678b8..8dbb41268b1 100644 --- a/src/typing/finalization.ml +++ b/src/typing/finalization.ml @@ -1,5 +1,6 @@ open Globals open Common +open Lookup open Type open Error open TyperBase diff --git a/src/typing/matcher/exprToPattern.ml b/src/typing/matcher/exprToPattern.ml index 3cb8edf06f4..3d6446cb0f3 100644 --- a/src/typing/matcher/exprToPattern.ml +++ b/src/typing/matcher/exprToPattern.ml @@ -446,4 +446,4 @@ let rec make pctx toplevel t e = fail() in let pat = loop e in - pat,p \ No newline at end of file + pat,p diff --git a/src/typing/typeload.ml b/src/typing/typeload.ml index 04b98056ffd..ecad6ddf320 100644 --- a/src/typing/typeload.ml +++ b/src/typing/typeload.ml @@ -895,4 +895,4 @@ let init_core_api ctx c = | Some cf, _ when not (has_class_field_flag cf CfPublic) -> () | Some f, Some f2 -> compare_fields f f2 | None, Some cf when not (has_class_field_flag cf CfPublic) -> () - | _ -> raise_typing_error "Constructor differs from core type" c.cl_pos) \ No newline at end of file + | _ -> raise_typing_error "Constructor differs from core type" c.cl_pos) diff --git a/src/typing/typeloadCheck.ml b/src/typing/typeloadCheck.ml index d9189bb0519..14f3169c440 100644 --- a/src/typing/typeloadCheck.ml +++ b/src/typing/typeloadCheck.ml @@ -334,20 +334,6 @@ let check_global_metadata ctx meta f_add mpath tpath so = ) ctx.com.global_metadata; if ctx.is_display_file then delay ctx PCheckConstraint (fun () -> DisplayEmitter.check_display_metadata ctx meta) -let check_module_types ctx m p t = - let t = t_infos t in - try - let path2 = ctx.com.module_lut#get_type_lut#find t.mt_path in - 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 - let s = if hex1 = hex2 then hex1 else Printf.sprintf "was %s, is %s" hex2 hex1 in - raise_typing_error (Printf.sprintf "Type name %s is redefined from module %s (%s)" (s_type_path t.mt_path) (s_type_path path2) s) p - with - Not_found -> - ctx.com.module_lut#get_type_lut#add t.mt_path m.m_path - module Inheritance = struct let is_basic_class_path path = match path with | ([],("Array" | "String" | "Date" | "Xml")) -> true diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index a34edc6c3e9..85d82c92926 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -957,7 +957,7 @@ module TypeBinding = struct | NothingToDo -> (fun () -> ()) | NormalOverride rctx -> - (fun () -> + (fun () -> TypeloadCheck.check_override_field ctx cf.cf_name_pos rctx ) | OverloadOverride f -> @@ -965,7 +965,7 @@ module TypeBinding = struct end | _ -> (fun () -> ()) - in + in let e = TypeloadFunction.type_function ctx args ret fmode e fctx.is_display_field p in f_check(); (* Disabled for now, see https://github.com/HaxeFoundation/haxe/issues/3033 *) @@ -1782,12 +1782,7 @@ let init_class ctx c p herits fields = | _ :: l -> check_require l in - let rec check_if_feature = function - | [] -> [] - | (Meta.IfFeature,el,_) :: _ -> List.map (fun (e,p) -> match e with EConst (String(s,_)) -> s | _ -> raise_typing_error "String expected" p) el - | _ :: l -> check_if_feature l - in - let cl_if_feature = check_if_feature c.cl_meta in + let cl_if_feature = Feature.check_if_feature c.cl_meta in let cl_req = check_require c.cl_meta in let has_init = ref false in List.iter (fun f -> @@ -1812,10 +1807,11 @@ let init_class ctx c p herits fields = | FKConstructor -> CfrConstructor | _ -> if fctx.is_static then CfrStatic else CfrMember in - ctx.m.curmod.m_extra.m_if_feature <- (s, (mk_class_field_ref c cf ref_kind fctx.is_macro)) :: ctx.m.curmod.m_extra.m_if_feature; + let cf_ref = mk_class_field_ref c cf ref_kind fctx.is_macro in + Feature.set_feature ctx.m.curmod cf_ref s; in List.iter set_feature cl_if_feature; - List.iter set_feature (check_if_feature cf.cf_meta); + List.iter set_feature (Feature.check_if_feature cf.cf_meta); let req = check_require f.cff_meta in let req = (match req with None -> if fctx.is_static || fctx.field_kind = FKConstructor then cl_req else None | _ -> req) in (match req with diff --git a/src/typing/typeloadModule.ml b/src/typing/typeloadModule.ml index 41d1738ce50..626d60b69db 100644 --- a/src/typing/typeloadModule.ml +++ b/src/typing/typeloadModule.ml @@ -55,7 +55,6 @@ module ModuleLevel = struct m let add_module ctx m p = - List.iter (TypeloadCheck.check_module_types ctx m p) m.m_types; ctx.com.module_lut#add m.m_path m (* @@ -380,15 +379,7 @@ module TypeLevel = struct ef_meta = c.ec_meta; } in DeprecationCheck.check_is ctx.com e.e_meta f.ef_meta f.ef_name f.ef_meta f.ef_name_pos; - let cf = { - (mk_field f.ef_name f.ef_type p f.ef_name_pos) with - cf_kind = (match follow f.ef_type with - | TFun _ -> Method MethNormal - | _ -> Var { v_read = AccNormal; v_write = AccNo } - ); - cf_doc = f.ef_doc; - cf_params = f.ef_params; - } in + let cf = class_field_of_enum_field f in if ctx.is_display_file && DisplayPosition.display_position#enclosed_in f.ef_name_pos then DisplayEmitter.display_enum_field ctx e f p; f,cf @@ -751,7 +742,10 @@ let type_types_into_module ctx m tdecls p = let ctx = create_typer_context_for_module ctx m in let decls,tdecls = ModuleLevel.create_module_types ctx m tdecls p in let types = List.map fst decls in - List.iter (TypeloadCheck.check_module_types ctx m p) types; + (* During the initial module_lut#add in type_module, m has no m_types yet by design. + We manually add them here. This and module_lut#add itself should be the only places + in the compiler that call add_module_type. *) + List.iter (fun mt -> ctx.com.module_lut#add_module_type m mt) types; m.m_types <- m.m_types @ types; (* define the per-module context for the next pass *) if ctx.g.std_types != null_module then begin diff --git a/src/typing/typer.ml b/src/typing/typer.ml index 31438deb0b2..745a8b6f702 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -1859,7 +1859,7 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) = else match e2.etype with | TAbstract({a_path = [],"Null"},[t]) -> tmin | _ -> follow_null tmin - in + in let e1 = vr#as_var "tmp" {e1 with etype = ctx.t.tnull tmin} in let e_null = Builder.make_null e1.etype e1.epos in let e_cond = mk (TBinop(OpNotEq,e1,e_null)) ctx.t.tbool e1.epos in diff --git a/src/typing/typerEntry.ml b/src/typing/typerEntry.ml index f7a854fd3c5..ff302b2e0c2 100644 --- a/src/typing/typerEntry.ml +++ b/src/typing/typerEntry.ml @@ -25,7 +25,7 @@ let create com macros = complete = false; type_hints = []; load_only_cached_modules = false; - functional_interface_lut = new pmap_lookup; + functional_interface_lut = new Lookup.pmap_lookup; do_macro = MacroContext.type_macro; do_load_macro = MacroContext.load_macro'; do_load_module = TypeloadModule.load_module; @@ -124,7 +124,7 @@ let create com macros = List.iter (fun mt -> match mt with | TClassDecl c -> ctx.g.std <- c; | _ -> () - ) m.m_types; + ) m.m_types; let m = TypeloadModule.load_module ctx ([],"Array") null_pos in (try List.iter (fun t -> ( @@ -151,4 +151,4 @@ let create com macros = ;; create_context_ref := create; -Inline.maybe_reapply_overload_call_ref := CallUnification.maybe_reapply_overload_call; \ No newline at end of file +Inline.maybe_reapply_overload_call_ref := CallUnification.maybe_reapply_overload_call; diff --git a/tests/server/src/Main.hx b/tests/server/src/Main.hx index e35a4cafcbe..77aa51ba3a0 100644 --- a/tests/server/src/Main.hx +++ b/tests/server/src/Main.hx @@ -13,4 +13,4 @@ class Main { report.displaySuccessResults = NeverShowSuccessResults; runner.run(); } -} \ No newline at end of file +} diff --git a/tests/server/src/cases/issues/Issue9690.hx b/tests/server/src/cases/issues/Issue9690.hx index 8faf398f559..f1bd5ca44f1 100644 --- a/tests/server/src/cases/issues/Issue9690.hx +++ b/tests/server/src/cases/issues/Issue9690.hx @@ -15,4 +15,4 @@ class Issue9690 extends TestCase { Assert.isTrue(lastResult.hasError); Assert.isTrue(lastResult.stderr.contains('Error: side effect!')); } -} \ No newline at end of file +} From 99bd8ef8fd4354b09b5efa420a8ad140b8580478 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Thu, 28 Dec 2023 22:09:37 +0100 Subject: [PATCH 049/184] [server] fix @:keep @:keep @:keep @:keep @:keep ... --- src/typing/finalization.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typing/finalization.ml b/src/typing/finalization.ml index 8dbb41268b1..406f6590c4f 100644 --- a/src/typing/finalization.ml +++ b/src/typing/finalization.ml @@ -43,7 +43,7 @@ let get_main ctx types = | _ -> raise_typing_error ("Invalid -main : " ^ s_type_path path ^ " has invalid main function") c.cl_pos in if not (ExtType.is_void (follow r)) then raise_typing_error (Printf.sprintf "Return type of main function should be Void (found %s)" (s_type (print_context()) r)) f.cf_name_pos; - f.cf_meta <- (Dce.mk_keep_meta f.cf_pos) :: f.cf_meta; + if not (Meta.has Meta.Keep f.cf_meta) then f.cf_meta <- (Dce.mk_keep_meta f.cf_pos) :: f.cf_meta; let emain = type_module_type ctx (TClassDecl c) null_pos in let main = mk (TCall (mk (TField (emain,fmode)) ft null_pos,[])) r null_pos in let call_static path method_name = From 2d821854378dc0c7c9aa0be0fca5aa3a3747edd1 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Fri, 29 Dec 2023 07:34:13 +0100 Subject: [PATCH 050/184] fix warnings --- src/context/common.ml | 6 +++--- src/typing/finalization.ml | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/context/common.ml b/src/context/common.ml index 6fbfba69569..2a94ab7c79a 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -313,11 +313,11 @@ class module_lut = object(self) with Not_found -> type_lut#add t.mt_path m.m_path - method add (path : path) (m : module_def) = + method! add (path : path) (m : module_def) = super#add path m; List.iter (fun mt -> self#add_module_type m mt) m.m_types - method remove (path : path) = + method! remove (path : path) = try List.iter (fun mt -> type_lut#remove (t_path mt)) (self#find path).m_types; super#remove path; @@ -327,7 +327,7 @@ class module_lut = object(self) method find_by_type (path : path) = self#find (type_lut#find path) - method clear = + method! clear = super#clear; type_lut#clear diff --git a/src/typing/finalization.ml b/src/typing/finalization.ml index 406f6590c4f..72b0847b5d0 100644 --- a/src/typing/finalization.ml +++ b/src/typing/finalization.ml @@ -1,6 +1,5 @@ open Globals open Common -open Lookup open Type open Error open TyperBase From 6f4a1071d28ef448fafa3f1d8f55dfc8e09c6ccc Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Fri, 29 Dec 2023 08:09:43 +0100 Subject: [PATCH 051/184] [typer] track type parameter hosts --- src/codegen/gencommon/closuresToClass.ml | 2 +- src/codegen/gencommon/gencommon.ml | 2 +- src/core/tFunctions.ml | 3 ++- src/core/tType.ml | 9 +++++++++ src/generators/genhl.ml | 2 +- src/macro/macroApi.ml | 2 +- src/typing/generic.ml | 2 +- src/typing/typeload.ml | 20 ++++++++------------ src/typing/typeloadFields.ml | 2 +- src/typing/typeloadFunction.ml | 6 +++--- src/typing/typer.ml | 2 +- 11 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/codegen/gencommon/closuresToClass.ml b/src/codegen/gencommon/closuresToClass.ml index d35bf652194..ed45fd75b44 100644 --- a/src/codegen/gencommon/closuresToClass.ml +++ b/src/codegen/gencommon/closuresToClass.ml @@ -393,7 +393,7 @@ let configure gen ft = in (*let cltypes = List.map (fun cl -> (snd cl.cl_path, TInst(map_param cl, []) )) tparams in*) - let cltypes = List.map (fun cl -> mk_type_param cl None None) tparams in + let cltypes = List.map (fun cl -> mk_type_param cl TPHType None None) tparams in (* create a new class that extends abstract function class, with a ctor implementation that will setup all captured variables *) let cfield = match gen.gcurrent_classfield with diff --git a/src/codegen/gencommon/gencommon.ml b/src/codegen/gencommon/gencommon.ml index 4dc998fc58e..d087d44ac3f 100644 --- a/src/codegen/gencommon/gencommon.ml +++ b/src/codegen/gencommon/gencommon.ml @@ -1142,7 +1142,7 @@ let clone_param ttp = let ret = mk_class cl.cl_module (fst cl.cl_path, snd cl.cl_path ^ "_c") cl.cl_pos null_pos in ret.cl_implements <- cl.cl_implements; ret.cl_kind <- cl.cl_kind; - let ttp = mk_type_param ret ttp.ttp_default ttp.ttp_constraints in + let ttp = mk_type_param ret ttp.ttp_host ttp.ttp_default ttp.ttp_constraints in ret.cl_kind <- KTypeParameter ttp; ttp diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index 12913bafa59..9b1ad7b0905 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -698,10 +698,11 @@ let lookup_param n l = in loop l -let mk_type_param c def constraints = { +let mk_type_param c host def constraints = { ttp_name = snd c.cl_path; ttp_type = TInst(c,[]); ttp_class = c; + ttp_host = host; ttp_constraints = constraints; ttp_default = def; } diff --git a/src/core/tType.ml b/src/core/tType.ml index 0cd1e2c8d27..3335a2ae77c 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -44,6 +44,14 @@ type module_cache_state = | MSBad of module_skip_reason | MSUnknown +type type_param_host = + | TPHType + | TPHConstructor + | TPHMethod + | TPHEnumConstructor + | TPHAnonField + | TPHLocal + type t = | TMono of tmono | TEnum of tenum * tparams @@ -93,6 +101,7 @@ and tparams = t list and typed_type_param = { ttp_name : string; ttp_class : tclass; + ttp_host : type_param_host; mutable ttp_type : t; mutable ttp_constraints : t list Lazy.t option; mutable ttp_default : t option; diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index 8ed3abbc49b..c378ab4bfbd 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -361,7 +361,7 @@ let make_debug ctx arr = let fake_tnull = {null_abstract with a_path = [],"Null"; - a_params = [mk_type_param null_class None None]; + a_params = [mk_type_param null_class TPHType None None]; } let get_rec_cache ctx t none_callback not_found_callback = diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index 69871e0629d..e6138c5da2c 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -2277,7 +2277,7 @@ let macro_api ccom get_api = | TInst(c,_) -> c | _ -> die "" __LOC__ in - mk_type_param c default None + mk_type_param c TPHType default None ) (decode_array tpl) in let rec map t = match t with | TInst({cl_kind = KTypeParameter _},_) -> diff --git a/src/typing/generic.ml b/src/typing/generic.ml index dda73fc982d..0dba901d33a 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -315,7 +315,7 @@ let build_generic_class ctx c p tl = | None -> None | Some constraints -> Some (lazy (List.map (generic_substitute_type gctx) (Lazy.force constraints))) in - let ttp' = mk_type_param c def constraints in + let ttp' = mk_type_param c ttp.ttp_host def constraints in (ttp.ttp_type,ttp') ) cf_old.cf_params in let param_subst = List.map (fun (t,ttp) -> t,(ttp.ttp_type,None)) params in diff --git a/src/typing/typeload.ml b/src/typing/typeload.ml index ecad6ddf320..956582e1c2e 100644 --- a/src/typing/typeload.ml +++ b/src/typing/typeload.ml @@ -35,7 +35,7 @@ open Globals let build_count = ref 0 -let type_function_params_rec = ref (fun _ _ _ _ -> die "" __LOC__) +let type_function_params_ref = ref (fun _ _ _ _ _ -> die "" __LOC__) let check_field_access ctx cff = let display_access = ref None in @@ -576,7 +576,7 @@ and load_complex_type' ctx allow_display (t,p) = no_expr e; topt t, Var { v_read = AccNormal; v_write = AccNormal } | FFun fd -> - params := (!type_function_params_rec) ctx fd (fst f.cff_name) p; + params := (!type_function_params_ref) ctx fd TPHAnonField (fst f.cff_name) p; no_expr fd.f_expr; let old = ctx.type_params in ctx.type_params <- !params @ old; @@ -673,7 +673,7 @@ and init_meta_overloads ctx co cf = not (List.mem t l) (* TODO: this still looks suspicious *) ) ctx.type_params end; - let params : type_params = (!type_function_params_rec) ctx f cf.cf_name p in + let params : type_params = (!type_function_params_ref) ctx f TPHMethod cf.cf_name p in ctx.type_params <- params @ ctx.type_params; let topt = function None -> raise_typing_error "Explicit type required" p | Some t -> load_complex_type ctx true t in let args = @@ -728,12 +728,6 @@ let load_type_hint ?(opt=false) ctx pcur t = (* ---------------------------------------------------------------------- *) (* PASS 1 & 2 : Module and Class Structure *) -type type_param_host = - | TPHType - | TPHConstructor - | TPHMethod - | TPHEnumConstructor - let rec type_type_param ctx host path get_params p tp = let n = fst tp.tp_name in let c = mk_class ctx.m.curmod (fst path @ [snd path],n) (pos tp.tp_name) (pos tp.tp_name) in @@ -754,7 +748,9 @@ let rec type_type_param ctx host path get_params p tp = () | TPHConstructor | TPHMethod - | TPHEnumConstructor -> + | TPHEnumConstructor + | TPHAnonField + | TPHLocal -> display_error ctx.com "Default type parameters are only supported on types" (pos ct) end; t @@ -763,7 +759,7 @@ let rec type_type_param ctx host path get_params p tp = in let ttp = match tp.tp_constraints with | None -> - mk_type_param c default None + mk_type_param c host default None | Some th -> let constraints = lazy ( let ctx = { ctx with type_params = ctx.type_params @ get_params() } in @@ -787,7 +783,7 @@ let rec type_type_param ctx host path get_params p tp = constr ) in delay ctx PConnectField (fun () -> ignore (Lazy.force constraints)); - mk_type_param c default (Some constraints) + mk_type_param c host default (Some constraints) in c.cl_kind <- KTypeParameter ttp; ttp diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index 85d82c92926..f8a45c83c9d 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -1295,7 +1295,7 @@ let setup_args_ret ctx cctx fctx name fd p = let create_method (ctx,cctx,fctx) c f fd p = let name = fst f.cff_name in - let params = TypeloadFunction.type_function_params ctx fd name p in + let params = TypeloadFunction.type_function_params ctx fd TPHMethod name p in if fctx.is_generic then begin if params = [] then raise_typing_error "Generic functions must have type parameters" p; end; diff --git a/src/typing/typeloadFunction.ml b/src/typing/typeloadFunction.ml index 3709c1798d2..48f106c30cf 100644 --- a/src/typing/typeloadFunction.ml +++ b/src/typing/typeloadFunction.ml @@ -43,9 +43,9 @@ let save_field_state ctx = ctx.in_function <- old_in_function; ) -let type_function_params ctx fd fname p = +let type_function_params ctx fd host fname p = let params = ref [] in - params := Typeload.type_type_params ctx TPHMethod ([],fname) (fun() -> !params) p fd.f_params; + params := Typeload.type_type_params ctx host ([],fname) (fun() -> !params) p fd.f_params; !params let type_function ctx (args : function_arguments) ret fmode e do_display p = @@ -257,4 +257,4 @@ let add_constructor ctx c force_constructor p = (* nothing to do *) () ;; -Typeload.type_function_params_rec := type_function_params +Typeload.type_function_params_ref := type_function_params diff --git a/src/typing/typer.ml b/src/typing/typer.ml index 745a8b6f702..5eced0b8b64 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -1218,7 +1218,7 @@ and type_map_declaration ctx e1 el with_type p = and type_local_function ctx kind f with_type p = let name,inline = match kind with FKNamed (name,inline) -> Some name,inline | _ -> None,false in - let params = TypeloadFunction.type_function_params ctx f (match name with None -> "localfun" | Some (n,_) -> n) p in + let params = TypeloadFunction.type_function_params ctx f TPHLocal (match name with None -> "localfun" | Some (n,_) -> n) p in if params <> [] then begin if name = None then display_error ctx.com "Type parameters not supported in unnamed local functions" p; if with_type <> WithType.NoValue then raise_typing_error "Type parameters are not supported for rvalue functions" p From 3b068a1e66cdc51e5571cf17fec6950df1514017 Mon Sep 17 00:00:00 2001 From: Zorbn <70043176+Zorbn@users.noreply.github.com> Date: Fri, 29 Dec 2023 00:35:22 -0800 Subject: [PATCH 052/184] Allow generating sourcemaps for Lua in the same format as JS (#11454) --- src/generators/genjs.ml | 151 ++------------------------------ src/generators/genlua.ml | 40 ++++++++- src/generators/jsSourcemap.ml | 159 ++++++++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+), 145 deletions(-) create mode 100644 src/generators/jsSourcemap.ml diff --git a/src/generators/genjs.ml b/src/generators/genjs.ml index 02a90e3427d..ba525b198e4 100644 --- a/src/generators/genjs.ml +++ b/src/generators/genjs.ml @@ -21,24 +21,7 @@ open Globals open Ast open Type open Common - -type sourcemap = { - sources : (string) DynArray.t; - sources_hash : (string, int) Hashtbl.t; - mappings : Rbuffer.t; - - mutable source_last_pos : sourcemap_pos; - mutable print_comma : bool; - mutable output_last_col : int; - mutable output_current_col : int; - mutable current_expr : sourcemap_pos option; -} - -and sourcemap_pos = { - file : int; - line : int; - col : int; -} +open JsSourcemap type ctx = { com : Common.context; @@ -169,98 +152,6 @@ let add_feature ctx = Common.add_feature ctx.com let unsupported p = abort "This expression cannot be compiled to Javascript" p -let encode_mapping smap pos = - if smap.print_comma then - Rbuffer.add_char smap.mappings ',' - else - smap.print_comma <- true; - - let base64_vlq number = - let encode_digit digit = - let chars = [| - 'A';'B';'C';'D';'E';'F';'G';'H';'I';'J';'K';'L';'M';'N';'O';'P'; - 'Q';'R';'S';'T';'U';'V';'W';'X';'Y';'Z';'a';'b';'c';'d';'e';'f'; - 'g';'h';'i';'j';'k';'l';'m';'n';'o';'p';'q';'r';'s';'t';'u';'v'; - 'w';'x';'y';'z';'0';'1';'2';'3';'4';'5';'6';'7';'8';'9';'+';'/' - |] in - Array.unsafe_get chars digit - in - let to_vlq number = - if number < 0 then - ((-number) lsl 1) + 1 - else - number lsl 1 - in - let rec loop vlq = - let shift = 5 in - let base = 1 lsl shift in - let mask = base - 1 in - let continuation_bit = base in - let digit = vlq land mask in - let next = vlq asr shift in - Rbuffer.add_char smap.mappings (encode_digit ( - if next > 0 then digit lor continuation_bit else digit)); - if next > 0 then loop next else () - in - loop (to_vlq number) - in - - base64_vlq (smap.output_current_col - smap.output_last_col); - base64_vlq (pos.file - smap.source_last_pos.file); - base64_vlq (pos.line - smap.source_last_pos.line); - base64_vlq (pos.col - smap.source_last_pos.col); - - smap.source_last_pos <- pos; - smap.output_last_col <- smap.output_current_col - -let noop () = () - -let add_mapping smap pos = - if pos.pmin < 0 then noop else - - let file = try - Hashtbl.find smap.sources_hash pos.pfile - with Not_found -> - let length = DynArray.length smap.sources in - Hashtbl.replace smap.sources_hash pos.pfile length; - DynArray.add smap.sources pos.pfile; - length - in - - let pos = - let line, col = Lexer.find_pos pos in - let line = line - 1 in - { file = file; line = line; col = col } - in - - if smap.source_last_pos <> pos then begin - let old_current_expr = smap.current_expr in - smap.current_expr <- Some pos; - encode_mapping smap pos; - (fun () -> smap.current_expr <- old_current_expr) - end else - noop - -let add_mapping ctx e = - Option.map_default (fun smap -> add_mapping smap e.epos) noop ctx.smap - -let handle_newlines ctx str = - Option.may (fun smap -> - let rec loop from = - try begin - let next = String.index_from str from '\n' + 1 in - Rbuffer.add_char smap.mappings ';'; - smap.output_last_col <- 0; - smap.output_current_col <- 0; - smap.print_comma <- false; - Option.may (encode_mapping smap) smap.current_expr; - loop next - end with Not_found -> - smap.output_current_col <- smap.output_current_col + (String.length str - from); - in - loop 0 - ) ctx.smap - let flush ctx = let chan = match ctx.chan with @@ -275,43 +166,16 @@ let flush ctx = let spr ctx s = ctx.separator <- false; - handle_newlines ctx s; + handle_newlines ctx.smap s; Rbuffer.add_string ctx.buf s let print ctx = ctx.separator <- false; Printf.kprintf (fun s -> begin - handle_newlines ctx s; + handle_newlines ctx.smap s; Rbuffer.add_string ctx.buf s end) -let write_mappings ctx smap = - let basefile = Filename.basename ctx.com.file in - print ctx "\n//# sourceMappingURL=%s.map" (url_encode_s basefile); - let channel = open_out_bin (ctx.com.file ^ ".map") in - let sources = DynArray.to_list smap.sources in - let to_url file = - ExtString.String.map (fun c -> if c == '\\' then '/' else c) (Path.get_full_path file) - in - output_string channel "{\n"; - output_string channel "\"version\":3,\n"; - output_string channel ("\"file\":\"" ^ (String.concat "\\\\" (ExtString.String.nsplit basefile "\\")) ^ "\",\n"); - output_string channel ("\"sourceRoot\":\"\",\n"); - output_string channel ("\"sources\":[" ^ - (String.concat "," (List.map (fun s -> "\"file:///" ^ to_url s ^ "\"") sources)) ^ - "],\n"); - if Common.defined ctx.com Define.SourceMapContent then begin - output_string channel ("\"sourcesContent\":[" ^ - (String.concat "," (List.map (fun s -> try "\"" ^ StringHelper.s_escape (Std.input_file ~bin:true s) ^ "\"" with _ -> "null") sources)) ^ - "],\n"); - end; - output_string channel "\"names\":[],\n"; - output_string channel "\"mappings\":\""; - Rbuffer.output_buffer channel smap.mappings; - output_string channel "\"\n"; - output_string channel "}"; - close_out channel - let newline ctx = match Rbuffer.nth ctx.buf (Rbuffer.length ctx.buf - 1) with | '}' | '{' | ':' | ';' when not ctx.separator -> print ctx "\n%s" ctx.tabs @@ -613,7 +477,7 @@ and add_objectdecl_parens e = loop e and gen_expr ctx e = - let clear_mapping = add_mapping ctx e in + let clear_mapping = add_mapping ctx.smap e in (match e.eexpr with | TConst c -> gen_constant ctx e.epos c | TLocal v -> spr ctx (ident v.v_name) @@ -978,7 +842,7 @@ and gen_block_element ?(newline_after=false) ?(keep_blocks=false) ctx e = if newline_after then newline ctx and gen_value ctx e = - let clear_mapping = add_mapping ctx e in + let clear_mapping = add_mapping ctx.smap e in let assign e = mk (TBinop (Ast.OpAssign, mk (TLocal (match ctx.in_value with None -> die "" __LOC__ | Some v -> v)) t_dynamic e.epos, @@ -2138,7 +2002,10 @@ let generate com = ); (match ctx.smap with - | Some smap -> write_mappings ctx smap + | Some smap -> + write_mappings ctx.com smap "file:///"; + let basefile = Filename.basename com.file in + print ctx "\n//# sourceMappingURL=%s.map" (url_encode_s basefile); | None -> try Sys.remove (com.file ^ ".map") with _ -> ()); flush ctx; Option.may (fun chan -> close_out chan) ctx.chan diff --git a/src/generators/genlua.ml b/src/generators/genlua.ml index 4dda9564ddd..4297cab5ed3 100644 --- a/src/generators/genlua.ml +++ b/src/generators/genlua.ml @@ -20,11 +20,13 @@ * DEALINGS IN THE SOFTWARE. *) +open Extlib_leftovers open Ast open Type open Common open ExtList open Error +open JsSourcemap type pos = Globals.pos @@ -32,6 +34,7 @@ type ctx = { com : Common.context; buf : Buffer.t; packages : (string list,unit) Hashtbl.t; + smap : sourcemap option; mutable current : tclass; mutable statics : (tclass * tclass_field * texpr) list; mutable inits : texpr list; @@ -143,11 +146,15 @@ let temp ctx = let spr ctx s = ctx.separator <- false; + handle_newlines ctx.smap s; Buffer.add_string ctx.buf s let print ctx = ctx.separator <- false; - Printf.kprintf (fun s -> Buffer.add_string ctx.buf s) + Printf.kprintf (fun s -> begin + handle_newlines ctx.smap s; + Buffer.add_string ctx.buf s + end) let newline ctx = print ctx "\n%s" ctx.tabs @@ -662,6 +669,7 @@ and lua_arg_name(a,_) = | _, _, _ -> ident a.v_name; and gen_expr ?(local=true) ctx e = begin + let clear_mapping = add_mapping ctx.smap e in match e.eexpr with TConst c -> gen_constant ctx e.epos c; @@ -1043,13 +1051,16 @@ and gen_expr ?(local=true) ctx e = begin | TCast (e1,None) -> gen_value ctx e1; | TIdent s -> - spr ctx s + spr ctx s; + + clear_mapping () end; (* gen_block_element handles expressions that map to "statements" in lua. *) (* It handles no-op situations, and ensures that expressions are formatted with newlines *) and gen_block_element ctx e = ctx.iife_assign <- false; + let clear_mapping = add_mapping ctx.smap e in begin match e.eexpr with | TTypeExpr _ | TConst _ | TLocal _ | TFunction _ -> () @@ -1109,6 +1120,7 @@ and gen_block_element ctx e = gen_expr ctx e; semicolon ctx; end; + clear_mapping () and is_const_null e = match e.eexpr with @@ -1147,6 +1159,7 @@ and gen_anon_value ctx e = gen_value ctx e and gen_value ctx e = + let clear_mapping = add_mapping ctx.smap e in let assign e = mk (TBinop (Ast.OpAssign, mk (TLocal (match ctx.in_value with None -> Globals.die "" __LOC__ | Some v -> v)) t_dynamic e.epos, @@ -1280,7 +1293,8 @@ and gen_value ctx e = gen_block_element ctx (mk (TTry (block (assign b), List.map (fun (v,e) -> v, block (assign e)) catchs )) e.etype e.epos); - v() + v(); + clear_mapping () and gen_tbinop ctx op e1 e2 = (match op, e1.eexpr, e2.eexpr with @@ -1866,10 +1880,26 @@ let generate_type_forward ctx = function | TTypeDecl _ | TAbstractDecl _ -> () let alloc_ctx com = + let smap = + if com.debug || Common.defined com Define.SourceMap then + Some { + source_last_pos = { file = 0; line = 0; col = 0}; + print_comma = false; + output_last_col = 0; + output_current_col = 0; + sources = DynArray.create(); + sources_hash = Hashtbl.create 0; + mappings = Rbuffer.create 16; + current_expr = None; + } + else + None + in let ctx = { com = com; buf = Buffer.create 16000; packages = Hashtbl.create 0; + smap = smap; statics = []; inits = []; current = null_class; @@ -2175,6 +2205,10 @@ let generate com = if anyExposed then println ctx "return _hx_exports"; + (match ctx.smap with + | Some smap -> write_mappings ctx.com smap "" + | None -> try Sys.remove (com.file ^ ".map") with _ -> ()); + let ch = open_out_bin com.file in output_string ch (Buffer.contents ctx.buf); close_out ch diff --git a/src/generators/jsSourcemap.ml b/src/generators/jsSourcemap.ml new file mode 100644 index 00000000000..ec81af7b375 --- /dev/null +++ b/src/generators/jsSourcemap.ml @@ -0,0 +1,159 @@ +(* + The Haxe Compiler + Copyright (C) 2005-2019 Haxe Foundation + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + *) +open Extlib_leftovers +open Globals +open Ast +open Type +open Common + +type sourcemap = { + sources : (string) DynArray.t; + sources_hash : (string, int) Hashtbl.t; + mappings : Rbuffer.t; + + mutable source_last_pos : sourcemap_pos; + mutable print_comma : bool; + mutable output_last_col : int; + mutable output_current_col : int; + mutable current_expr : sourcemap_pos option; +} + +and sourcemap_pos = { + file : int; + line : int; + col : int; +} + +let encode_mapping smap pos = + if smap.print_comma then + Rbuffer.add_char smap.mappings ',' + else + smap.print_comma <- true; + + let base64_vlq number = + let encode_digit digit = + let chars = [| + 'A';'B';'C';'D';'E';'F';'G';'H';'I';'J';'K';'L';'M';'N';'O';'P'; + 'Q';'R';'S';'T';'U';'V';'W';'X';'Y';'Z';'a';'b';'c';'d';'e';'f'; + 'g';'h';'i';'j';'k';'l';'m';'n';'o';'p';'q';'r';'s';'t';'u';'v'; + 'w';'x';'y';'z';'0';'1';'2';'3';'4';'5';'6';'7';'8';'9';'+';'/' + |] in + Array.unsafe_get chars digit + in + let to_vlq number = + if number < 0 then + ((-number) lsl 1) + 1 + else + number lsl 1 + in + let rec loop vlq = + let shift = 5 in + let base = 1 lsl shift in + let mask = base - 1 in + let continuation_bit = base in + let digit = vlq land mask in + let next = vlq asr shift in + Rbuffer.add_char smap.mappings (encode_digit ( + if next > 0 then digit lor continuation_bit else digit)); + if next > 0 then loop next else () + in + loop (to_vlq number) + in + + base64_vlq (smap.output_current_col - smap.output_last_col); + base64_vlq (pos.file - smap.source_last_pos.file); + base64_vlq (pos.line - smap.source_last_pos.line); + base64_vlq (pos.col - smap.source_last_pos.col); + + smap.source_last_pos <- pos; + smap.output_last_col <- smap.output_current_col + +let noop () = () + +let add_mapping smap pos = + if pos.pmin < 0 then noop else + + let file = try + Hashtbl.find smap.sources_hash pos.pfile + with Not_found -> + let length = DynArray.length smap.sources in + Hashtbl.replace smap.sources_hash pos.pfile length; + DynArray.add smap.sources pos.pfile; + length + in + + let pos = + let line, col = Lexer.find_pos pos in + let line = line - 1 in + { file = file; line = line; col = col } + in + + if smap.source_last_pos <> pos then begin + let old_current_expr = smap.current_expr in + smap.current_expr <- Some pos; + encode_mapping smap pos; + (fun () -> smap.current_expr <- old_current_expr) + end else + noop + +let add_mapping smap e = + Option.map_default (fun smap -> add_mapping smap e.epos) noop smap + +let handle_newlines smap str = + Option.may (fun smap -> + let rec loop from = + try begin + let next = String.index_from str from '\n' + 1 in + Rbuffer.add_char smap.mappings ';'; + smap.output_last_col <- 0; + smap.output_current_col <- 0; + smap.print_comma <- false; + Option.may (encode_mapping smap) smap.current_expr; + loop next + end with Not_found -> + smap.output_current_col <- smap.output_current_col + (String.length str - from); + in + loop 0 + ) smap + +let write_mappings (com : Common.context) smap source_path_prefix = + let basefile = Filename.basename com.file in + let channel = open_out_bin (com.file ^ ".map") in + let sources = DynArray.to_list smap.sources in + let to_url file = + ExtString.String.map (fun c -> if c == '\\' then '/' else c) (Path.get_full_path file) + in + output_string channel "{\n"; + output_string channel "\"version\":3,\n"; + output_string channel ("\"file\":\"" ^ (String.concat "\\\\" (ExtString.String.nsplit basefile "\\")) ^ "\",\n"); + output_string channel ("\"sourceRoot\":\"\",\n"); + output_string channel ("\"sources\":[" ^ + (String.concat "," (List.map (fun s -> "\"" ^ source_path_prefix ^ to_url s ^ "\"") sources)) ^ + "],\n"); + if Common.defined com Define.SourceMapContent then begin + output_string channel ("\"sourcesContent\":[" ^ + (String.concat "," (List.map (fun s -> try "\"" ^ StringHelper.s_escape (Std.input_file ~bin:true s) ^ "\"" with _ -> "null") sources)) ^ + "],\n"); + end; + output_string channel "\"names\":[],\n"; + output_string channel "\"mappings\":\""; + Rbuffer.output_buffer channel smap.mappings; + output_string channel "\"\n"; + output_string channel "}"; + close_out channel \ No newline at end of file From 45f7252bf393eb3190f11060874ec40d7f5fc755 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Fri, 29 Dec 2023 13:14:57 +0100 Subject: [PATCH 053/184] [typer] fix type parameter resolution related to meta overloads --- src/typing/typeload.ml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/typing/typeload.ml b/src/typing/typeload.ml index 956582e1c2e..21cbe64efb9 100644 --- a/src/typing/typeload.ml +++ b/src/typing/typeload.ml @@ -669,8 +669,8 @@ and init_meta_overloads ctx co cf = | [] -> () | l -> - ctx.type_params <- List.filter (fun t -> - not (List.mem t l) (* TODO: this still looks suspicious *) + ctx.type_params <- List.filter (fun ttp -> + ttp.ttp_host <> TPHMethod ) ctx.type_params end; let params : type_params = (!type_function_params_ref) ctx f TPHMethod cf.cf_name p in @@ -761,8 +761,9 @@ let rec type_type_param ctx host path get_params p tp = | None -> mk_type_param c host default None | Some th -> + let current_type_params = ctx.type_params in let constraints = lazy ( - let ctx = { ctx with type_params = ctx.type_params @ get_params() } in + let ctx = { ctx with type_params = get_params() @ current_type_params } in let rec loop th = match fst th with | CTIntersection tl -> List.map (load_complex_type ctx true) tl | CTParent ct -> loop ct From 5850ef1b14ece8446d561b7b919fc52fb7bfcf20 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Fri, 29 Dec 2023 14:23:19 +0100 Subject: [PATCH 054/184] [generic] point to the correct ttp and add ttp printer --- src/codegen/codegen.ml | 2 +- src/core/tPrinting.ml | 46 ++++++++++++++++++++++++------------------ src/typing/generic.ml | 1 + 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/codegen/codegen.ml b/src/codegen/codegen.ml index a40ab712126..5c945905bf4 100644 --- a/src/codegen/codegen.ml +++ b/src/codegen/codegen.ml @@ -244,7 +244,7 @@ module Dump = struct let s_type = s_type (Type.print_context()) in let params tl = match tl with | [] -> "" - | l -> Printf.sprintf "<%s>" (String.concat ", " (List.map Printer.s_type_param l)) + | l -> Printf.sprintf "<%s>" (String.concat ", " (List.map (Printer.s_type_param "") l)) in List.iter (fun mt -> let path = Type.t_path mt in diff --git a/src/core/tPrinting.ml b/src/core/tPrinting.ml index 4a3e1522ca8..31399d79890 100644 --- a/src/core/tPrinting.ml +++ b/src/core/tPrinting.ml @@ -441,20 +441,26 @@ module Printer = struct let s_metadata metadata = s_list " " s_metadata_entry metadata - let s_type_param ttp = - let s = match (get_constraints ttp) with - | [] -> ttp.ttp_name - | tl1 -> Printf.sprintf "%s:%s" ttp.ttp_name (String.concat " & " (List.map s_type tl1)) - in - begin match ttp.ttp_default with - | None -> - s - | Some t -> - Printf.sprintf "%s = %s" s (s_type t) - end + let s_ttp_host = function + | TPHType -> "TPHType" + | TPHConstructor -> "TPHConstructor" + | TPHMethod -> "TPHMethod" + | TPHEnumConstructor -> "TPHEnumConstructor" + | TPHAnonField -> "TPHAnonField" + | TPHLocal -> "TPHLocal" + + let s_type_param tabs ttp = + s_record_fields tabs [ + "name",ttp.ttp_name; + "class",s_type_path ttp.ttp_class.cl_path; + "host",s_ttp_host ttp.ttp_host; + "type",s_type_kind ttp.ttp_type; + "constraints",s_list ", " s_type_kind (get_constraints ttp) ; + "default",s_opt s_type_kind ttp.ttp_default; + ] - let s_type_params tl = - s_list ", " s_type_param tl + let s_type_params tabs tl = + s_list ", " (s_type_param tabs) tl let s_tclass_field_flags flags = s_flags flags flag_tclass_field_names @@ -468,7 +474,7 @@ module Printer = struct "cf_name_pos",s_pos cf.cf_name_pos; "cf_meta",s_metadata cf.cf_meta; "cf_kind",s_kind cf.cf_kind; - "cf_params",s_type_params cf.cf_params; + "cf_params",s_type_params (tabs ^ "\t") cf.cf_params; "cf_expr",s_opt (s_expr_ast true "\t\t" s_type) cf.cf_expr; "cf_flags",s_tclass_field_flags cf.cf_flags; ] @@ -482,7 +488,7 @@ module Printer = struct "cl_private",string_of_bool c.cl_private; "cl_doc",s_doc c.cl_doc; "cl_meta",s_metadata c.cl_meta; - "cl_params",s_type_params c.cl_params; + "cl_params",s_type_params (tabs ^ "\t") c.cl_params; "cl_kind",s_class_kind c.cl_kind; "cl_super",s_opt (fun (c,tl) -> s_type (TInst(c,tl))) c.cl_super; "cl_implements",s_list ", " (fun (c,tl) -> s_type (TInst(c,tl))) c.cl_implements; @@ -502,7 +508,7 @@ module Printer = struct "t_private",string_of_bool t.t_private; "t_doc",s_doc t.t_doc; "t_meta",s_metadata t.t_meta; - "t_params",s_type_params t.t_params; + "t_params",s_type_params (tabs ^ "\t") t.t_params; "t_type",s_type_kind t.t_type ] @@ -514,7 +520,7 @@ module Printer = struct "ef_name_pos",s_pos ef.ef_name_pos; "ef_type",s_type_kind ef.ef_type; "ef_index",string_of_int ef.ef_index; - "ef_params",s_type_params ef.ef_params; + "ef_params",s_type_params (tabs ^ "\t") ef.ef_params; "ef_meta",s_metadata ef.ef_meta ] @@ -527,7 +533,7 @@ module Printer = struct "e_private",string_of_bool en.e_private; "d_doc",s_doc en.e_doc; "e_meta",s_metadata en.e_meta; - "e_params",s_type_params en.e_params; + "e_params",s_type_params (tabs ^ "\t") en.e_params; "e_type",s_type_kind en.e_type; "e_extern",string_of_bool en.e_extern; "e_constrs",s_list "\n\t" (s_tenum_field (tabs ^ "\t")) (PMap.fold (fun ef acc -> ef :: acc) en.e_constrs []); @@ -543,7 +549,7 @@ module Printer = struct "a_private",string_of_bool a.a_private; "a_doc",s_doc a.a_doc; "a_meta",s_metadata a.a_meta; - "a_params",s_type_params a.a_params; + "a_params",s_type_params (tabs ^ "\t") a.a_params; "a_ops",s_list ", " (fun (op,cf) -> Printf.sprintf "%s: %s" (s_binop op) cf.cf_name) a.a_ops; "a_unops",s_list ", " (fun (op,flag,cf) -> Printf.sprintf "%s (%s): %s" (s_unop op) (if flag = Postfix then "postfix" else "prefix") cf.cf_name) a.a_unops; "a_impl",s_opt (fun c -> s_type_path c.cl_path) a.a_impl; @@ -558,7 +564,7 @@ module Printer = struct ] let s_tvar_extra ve = - Printf.sprintf "Some(%s, %s)" (s_type_params ve.v_params) (s_opt (s_expr_ast true "" s_type) ve.v_expr) + Printf.sprintf "Some(%s, %s)" (s_type_params "" ve.v_params) (s_opt (s_expr_ast true "" s_type) ve.v_expr) let s_tvar v = s_record_fields "" [ diff --git a/src/typing/generic.ml b/src/typing/generic.ml index 0dba901d33a..a1e3fc7e411 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -316,6 +316,7 @@ let build_generic_class ctx c p tl = | Some constraints -> Some (lazy (List.map (generic_substitute_type gctx) (Lazy.force constraints))) in let ttp' = mk_type_param c ttp.ttp_host def constraints in + c.cl_kind <- KTypeParameter ttp'; (ttp.ttp_type,ttp') ) cf_old.cf_params in let param_subst = List.map (fun (t,ttp) -> t,(ttp.ttp_type,None)) params in From 22158007b0cc2961feb33dfab6098127172f2070 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Fri, 29 Dec 2023 17:59:46 +0100 Subject: [PATCH 055/184] fix type parameter pretty dumping --- src/codegen/codegen.ml | 13 +++++++++---- src/core/tPrinting.ml | 12 ++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/codegen/codegen.ml b/src/codegen/codegen.ml index 5c945905bf4..252d3a8cfce 100644 --- a/src/codegen/codegen.ml +++ b/src/codegen/codegen.ml @@ -240,11 +240,16 @@ module Dump = struct let buf,close = create_dumpfile [] ((dump_path com) :: (platform_name_macro com) :: fst path @ [snd path]) in buf,close - let dump_types com s_expr = + let dump_types com pretty = let s_type = s_type (Type.print_context()) in + let s_expr,s_type_param = if pretty then + (Type.s_expr_ast (not (Common.defined com Define.DumpIgnoreVarIds)) "\t"),(s_type_param s_type) + else + (Type.s_expr_pretty false "\t" true),(Printer.s_type_param "") + in let params tl = match tl with | [] -> "" - | l -> Printf.sprintf "<%s>" (String.concat ", " (List.map (Printer.s_type_param "") l)) + | l -> Printf.sprintf "<%s>" (String.concat ", " (List.map s_type_param l)) in List.iter (fun mt -> let path = Type.t_path mt in @@ -376,10 +381,10 @@ module Dump = struct let dump_types com = match Common.defined_value_safe com Define.Dump with - | "pretty" -> dump_types com (Type.s_expr_pretty false "\t" true) + | "pretty" -> dump_types com true | "record" -> dump_record com | "position" -> dump_position com - | _ -> dump_types com (Type.s_expr_ast (not (Common.defined com Define.DumpIgnoreVarIds)) "\t") + | _ -> dump_types com false let dump_dependencies ?(target_override=None) com = let target_name = match target_override with diff --git a/src/core/tPrinting.ml b/src/core/tPrinting.ml index 31399d79890..23ea68ef515 100644 --- a/src/core/tPrinting.ml +++ b/src/core/tPrinting.ml @@ -128,6 +128,18 @@ and s_constraint = function | MOpenStructure -> "MOpenStructure" | MEmptyStructure -> "MEmptyStructure" +let s_type_param s_type ttp = + let s = match (get_constraints ttp) with + | [] -> ttp.ttp_name + | tl1 -> Printf.sprintf "%s:%s" ttp.ttp_name (String.concat " & " (List.map s_type tl1)) + in + begin match ttp.ttp_default with + | None -> + s + | Some t -> + Printf.sprintf "%s = %s" s (s_type t) + end + let s_access is_read = function | AccNormal -> "default" | AccNo -> "null" From ce7bb5d94dd932ea6499e540b61869ae5f688c95 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Fri, 29 Dec 2023 22:56:13 +0100 Subject: [PATCH 056/184] that's not pretty... --- src/codegen/codegen.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/codegen/codegen.ml b/src/codegen/codegen.ml index 252d3a8cfce..393b5c88a31 100644 --- a/src/codegen/codegen.ml +++ b/src/codegen/codegen.ml @@ -242,10 +242,10 @@ module Dump = struct let dump_types com pretty = let s_type = s_type (Type.print_context()) in - let s_expr,s_type_param = if pretty then - (Type.s_expr_ast (not (Common.defined com Define.DumpIgnoreVarIds)) "\t"),(s_type_param s_type) + let s_expr,s_type_param = if not pretty then + (Type.s_expr_ast (not (Common.defined com Define.DumpIgnoreVarIds)) "\t"),(Printer.s_type_param "") else - (Type.s_expr_pretty false "\t" true),(Printer.s_type_param "") + (Type.s_expr_pretty false "\t" true),(s_type_param s_type) in let params tl = match tl with | [] -> "" From 64f141b9b3366d6af99f5fb7fc99302c5f720439 Mon Sep 17 00:00:00 2001 From: fourst4r Date: Sat, 30 Dec 2023 19:44:01 +1300 Subject: [PATCH 057/184] Update hxcpp defines (#11455) Still not a complete list of hxcpp defines, but these are some useful ones --- src-json/define.json | 108 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/src-json/define.json b/src-json/define.json index e95cc7ff095..dfc8de2f6ca 100644 --- a/src-json/define.json +++ b/src-json/define.json @@ -319,6 +319,114 @@ "doc": "Include additional information for hxcpp-debugger.", "platforms": ["cpp"] }, + { + "name": "HxcppGcMoving", + "define": "HXCPP-GC-MOVING", + "doc": "Allow garbage collector to move memory to reduce fragmentation", + "platforms": ["cpp"] + }, + { + "name": "HxcppGcSummary", + "define": "HXCPP-GC-SUMMARY", + "doc": "Print small profiling summary at end of program", + "platforms": ["cpp"] + }, + { + "name": "HxcppGcDynamicSize", + "define": "HXCPP-GC-DYNAMIC-SIZE", + "doc": "Monitor GC times and expand memory working space if required", + "platforms": ["cpp"] + }, + { + "name": "HxcppGcBigBlocks", + "define": "HXCPP-GC-BIG-BLOCKS", + "doc": "Allow working memory greater than 1 Gig", + "platforms": ["cpp"] + }, + { + "name": "HxcppGcDebugLevel", + "define": "HXCPP-GC-DEBUG-LEVEL", + "doc": "Number 1-4 indicating additional debugging in GC", + "platforms": ["cpp"] + }, + { + "name": "HxcppDebugLink", + "define": "HXCPP-DEBUG-LINK", + "doc": "Add symbols to final binary, even in release mode.", + "platforms": ["cpp"] + }, + { + "name": "HxcppStackTrace", + "define": "HXCPP-STACK-TRACE", + "doc": "Have valid function-level stack traces, even in release mode.", + "platforms": ["cpp"] + }, + { + "name": "HxcppStackLine", + "define": "HXCPP-STACK-LINE", + "doc": "Include line information in stack traces, even in release mode.", + "platforms": ["cpp"] + }, + { + "name": "HxcppCheckPointer", + "define": "HXCPP-CHECK-POINTER", + "doc": "Add null-pointer checks, even in release mode.", + "platforms": ["cpp"] + }, + { + "name": "HxcppProfiler", + "define": "HXCPP-PROFILER", + "doc": "Add profiler support", + "platforms": ["cpp"] + }, + { + "name": "HxcppTelemetry", + "define": "HXCPP-TELEMETRY", + "doc": "Add telemetry support", + "platforms": ["cpp"] + }, + { + "name": "HxcppCpp11", + "define": "HXCPP-CPP11", + "doc": "Use C++11 features and link libraries", + "platforms": ["cpp"] + }, + { + "name": "HxcppVerbose", + "define": "HXCPP-VERBOSE", + "doc": "Print extra output from build tool.", + "platforms": ["cpp"] + }, + { + "name": "HxcppTimes", + "define": "HXCPP-TIMES", + "doc": "Show some basic profiling information", + "platforms": ["cpp"] + }, + { + "name": "HxcppM32", + "define": "HXCPP-M32", + "doc": "Force 32-bit compile for current desktop", + "platforms": ["cpp"] + }, + { + "name": "HxcppM64", + "define": "HXCPP-M64", + "doc": "Force 64-bit compile for current desktop", + "platforms": ["cpp"] + }, + { + "name": "HxcppArm64", + "define": "HXCPP-ARM64", + "doc": "Compile arm-based devices for 64 bits", + "platforms": ["cpp"] + }, + { + "name": "HxcppLinuxArm64", + "define": "HXCPP-LINUX-ARM64", + "doc": "Run on a linux ARM64 device", + "platforms": ["cpp"] + }, { "name": "HxcppSmartStings", "define": "hxcpp-smart-strings", From 580cacd45ddc14c9c37c0a9d652f7f6ed79c48be Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Sat, 30 Dec 2023 09:37:04 +0100 Subject: [PATCH 058/184] [server] generalize cache-bound object handling see #7851 --- src/compiler/server.ml | 12 ++++++++++-- src/core/tFunctions.ml | 2 +- src/core/tType.ml | 6 +++++- src/macro/macroApi.ml | 4 +++- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/compiler/server.ml b/src/compiler/server.ml index de6edffc75c..48da21090f7 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -395,6 +395,14 @@ let check_module sctx ctx m p = end; state +let handle_cache_bound_objects com cbol = + List.iter (function + | Resource(name,data) -> + Hashtbl.replace com.resources name data + | IncludeFile(file,position) -> + com.include_files <- (file,position) :: com.include_files + ) cbol + (* Adds module [m] and all its dependencies (recursively) from the cache to the current compilation context. *) let add_modules sctx ctx m p = @@ -404,7 +412,7 @@ let add_modules sctx ctx m p = (match m0.m_extra.m_kind, m.m_extra.m_kind with | MCode, MMacro | MMacro, MCode -> (* this was just a dependency to check : do not add to the context *) - PMap.iter (Hashtbl.replace com.resources) m.m_extra.m_binded_res; + handle_cache_bound_objects com m.m_extra.m_cache_bound_objects; | _ -> m.m_extra.m_added <- ctx.com.compilation_step; ServerMessage.reusing com tabs m; @@ -412,7 +420,7 @@ let add_modules sctx ctx m p = (t_infos t).mt_restore() ) m.m_types; TypeloadModule.ModuleLevel.add_module ctx m p; - PMap.iter (Hashtbl.replace com.resources) m.m_extra.m_binded_res; + handle_cache_bound_objects com m.m_extra.m_cache_bound_objects; PMap.iter (fun _ (sign,mpath) -> let m2 = (com.cs#get_context sign)#find_module mpath in add_modules (tabs ^ " ") m0 m2 diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index 9b1ad7b0905..bbcb8a2db60 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -166,7 +166,7 @@ let module_extra file sign time kind policy = m_processed = 0; m_deps = PMap.empty; m_kind = kind; - m_binded_res = PMap.empty; + m_cache_bound_objects = []; m_if_feature = []; m_features = Hashtbl.create 0; m_check_policy = policy; diff --git a/src/core/tType.ml b/src/core/tType.ml index 3335a2ae77c..cbc53d9d781 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -52,6 +52,10 @@ type type_param_host = | TPHAnonField | TPHLocal +type cache_bound_object = + | Resource of string * string + | IncludeFile of string * string + type t = | TMono of tmono | TEnum of tenum * tparams @@ -403,7 +407,7 @@ and module_def_extra = { mutable m_processed : int; mutable m_deps : (int,(string (* sign *) * path)) PMap.t; mutable m_kind : module_kind; - mutable m_binded_res : (string, string) PMap.t; + mutable m_cache_bound_objects : cache_bound_object list; mutable m_if_feature : (string * class_field_ref) list; mutable m_features : (string,bool) Hashtbl.t; } diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index e6138c5da2c..0fa4dabe39d 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -2088,7 +2088,7 @@ let macro_api ccom get_api = if name = "" then failwith "Empty resource name"; Hashtbl.replace (ccom()).resources name data; let m = (get_api()).current_module() in - m.m_extra.m_binded_res <- PMap.add name data m.m_extra.m_binded_res; + m.m_extra.m_cache_bound_objects <- (Resource(name,data)) :: m.m_extra.m_cache_bound_objects; vnull ); "get_resources", vfun0 (fun() -> @@ -2301,6 +2301,8 @@ let macro_api ccom get_api = failwith ("unable to find file for inclusion: " ^ file) in (ccom()).include_files <- (file, position) :: (ccom()).include_files; + let m = (get_api()).current_module() in + m.m_extra.m_cache_bound_objects <- (IncludeFile(file,position)) :: m.m_extra.m_cache_bound_objects; vnull ); (* Compilation server *) From 94857d2b859385f51c5d657b61636e062a7dfa91 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Mon, 1 Jan 2024 11:29:54 +0100 Subject: [PATCH 059/184] Happy new year! --- src/compiler/args.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/args.ml b/src/compiler/args.ml index 4b6a17841e1..48f010f4c04 100644 --- a/src/compiler/args.ml +++ b/src/compiler/args.ml @@ -42,7 +42,7 @@ let process_args arg_spec = let parse_args com = let usage = Printf.sprintf - "Haxe Compiler %s - (C)2005-2023 Haxe Foundation\nUsage: haxe%s [options] [hxml files and dot paths...]\n" + "Haxe Compiler %s - (C)2005-2024 Haxe Foundation\nUsage: haxe%s [options] [hxml files and dot paths...]\n" s_version_full (if Sys.os_type = "Win32" then ".exe" else "") in let actx = { From 72252ad44e7780e4e43377a52f803710063d7a59 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Mon, 1 Jan 2024 17:29:45 +0100 Subject: [PATCH 060/184] [typer] fix functional interface type parameter leak see #11390 --- src/context/abstractCast.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/context/abstractCast.ml b/src/context/abstractCast.ml index 62afbfc23ec..b26f26d980d 100644 --- a/src/context/abstractCast.ml +++ b/src/context/abstractCast.ml @@ -88,7 +88,9 @@ and do_check_cast ctx uctx tleft eright p = end | TInst(c,tl), TFun _ when has_class_flag c CFunctionalInterface -> let cf = ctx.g.functional_interface_lut#find c.cl_path in - unify_raise_custom uctx eright.etype (apply_params c.cl_params tl cf.cf_type) p; + let map = apply_params c.cl_params tl in + let monos = Monomorph.spawn_constrained_monos map cf.cf_params in + unify_raise_custom uctx eright.etype (map (apply_params cf.cf_params monos cf.cf_type)) p; eright | _ -> raise Not_found From bc9c91d098492a5e4300816542cfd72073db68ea Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Tue, 2 Jan 2024 10:08:16 +0100 Subject: [PATCH 061/184] [display] file diagnostics should be DFPOnly --- src/compiler/displayProcessing.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/displayProcessing.ml b/src/compiler/displayProcessing.ml index 8bfc95efab8..aa25ae6008c 100644 --- a/src/compiler/displayProcessing.ml +++ b/src/compiler/displayProcessing.ml @@ -48,7 +48,7 @@ let handle_display_argument_old com file_pos actx = | "diagnostics" -> com.report_mode <- RMLegacyDiagnostics [file_unique]; let dm = create DMNone in - {dm with dms_display_file_policy = DFPAlso; dms_per_file = true; dms_populate_cache = !ServerConfig.populate_cache_from_display} + {dm with dms_display_file_policy = DFPOnly; dms_per_file = true; dms_populate_cache = !ServerConfig.populate_cache_from_display} | "statistics" -> com.report_mode <- RMStatistics; let dm = create DMNone in From eb3d93643ea7af643239a13f427dcbad56befc99 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Tue, 2 Jan 2024 10:24:49 +0100 Subject: [PATCH 062/184] [server] turn module_tainting_reason into a type --- src/context/display/displayJson.ml | 2 +- src/context/display/displayTexpr.ml | 2 +- src/core/tPrinting.ml | 7 ++++++- src/core/tType.ml | 7 ++++++- src/generators/jsSourcemap.ml | 1 - src/macro/macroApi.ml | 4 ++-- tests/server/src/cases/issues/Issue9690.hx | 2 +- tests/unit/src/unit/TestOverloads.hx | 1 + 8 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/context/display/displayJson.ml b/src/context/display/displayJson.ml index 986a86ee285..772fb15662b 100644 --- a/src/context/display/displayJson.ml +++ b/src/context/display/displayJson.ml @@ -378,7 +378,7 @@ let handler = let file = hctx.jsonrpc#get_string_param "file" in let fkey = hctx.com.file_keys#get file in let cs = hctx.display#get_cs in - cs#taint_modules fkey "server/invalidate"; + cs#taint_modules fkey ServerInvalidate; cs#remove_files fkey; hctx.send_result jnull ); diff --git a/src/context/display/displayTexpr.ml b/src/context/display/displayTexpr.ml index b6fa148e6b5..f5241cdb35c 100644 --- a/src/context/display/displayTexpr.ml +++ b/src/context/display/displayTexpr.ml @@ -178,7 +178,7 @@ let check_display_file ctx cs = let fkey = DisplayPosition.display_position#get_file_key in (* force parsing again : if the completion point have been changed *) cs#remove_files fkey; - cs#taint_modules fkey "check_display_file"; + cs#taint_modules fkey CheckDisplayFile; end | None -> () diff --git a/src/core/tPrinting.ml b/src/core/tPrinting.ml index 23ea68ef515..6361b497d0a 100644 --- a/src/core/tPrinting.ml +++ b/src/core/tPrinting.ml @@ -610,11 +610,16 @@ module Printer = struct | MExtern -> "MExtern" | MImport -> "MImport" + let s_module_tainting_reason = function + | CheckDisplayFile -> "check_display_file" + | ServerInvalidate -> "server/invalidate" + | ServerInvalidateFiles -> "server_invalidate_files" + let s_module_skip_reason reason = let rec loop stack = function | DependencyDirty(path,reason) -> (Printf.sprintf "%s%s - %s" (if stack = [] then "DependencyDirty " else "") (s_type_path path) (if List.mem path stack then "rec" else loop (path :: stack) reason)) - | Tainted cause -> "Tainted " ^ cause + | Tainted cause -> "Tainted " ^ (s_module_tainting_reason cause) | FileChanged file -> "FileChanged " ^ file | Shadowed file -> "Shadowed " ^ file | LibraryChanged -> "LibraryChanged" diff --git a/src/core/tType.ml b/src/core/tType.ml index cbc53d9d781..d601575c77e 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -32,9 +32,14 @@ type module_check_policy = | NoCheckShadowing | Retype +type module_tainting_reason = + | CheckDisplayFile + | ServerInvalidate + | ServerInvalidateFiles + type module_skip_reason = | DependencyDirty of path * module_skip_reason - | Tainted of string + | Tainted of module_tainting_reason | FileChanged of string | Shadowed of string | LibraryChanged diff --git a/src/generators/jsSourcemap.ml b/src/generators/jsSourcemap.ml index ec81af7b375..f44a2029162 100644 --- a/src/generators/jsSourcemap.ml +++ b/src/generators/jsSourcemap.ml @@ -18,7 +18,6 @@ *) open Extlib_leftovers open Globals -open Ast open Type open Common diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index 0fa4dabe39d..952241ee0ba 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -2276,7 +2276,7 @@ let macro_api ccom get_api = let c = match t with | TInst(c,_) -> c | _ -> die "" __LOC__ - in + in mk_type_param c TPHType default None ) (decode_array tpl) in let rec map t = match t with @@ -2318,7 +2318,7 @@ let macro_api ccom get_api = List.iter (fun v -> let s = decode_string v in let s = com.file_keys#get s in - cs#taint_modules s "server_invalidate_files"; + cs#taint_modules s ServerInvalidateFiles; cs#remove_files s; ) (decode_array a); vnull diff --git a/tests/server/src/cases/issues/Issue9690.hx b/tests/server/src/cases/issues/Issue9690.hx index f1bd5ca44f1..8faf398f559 100644 --- a/tests/server/src/cases/issues/Issue9690.hx +++ b/tests/server/src/cases/issues/Issue9690.hx @@ -15,4 +15,4 @@ class Issue9690 extends TestCase { Assert.isTrue(lastResult.hasError); Assert.isTrue(lastResult.stderr.contains('Error: side effect!')); } -} +} \ No newline at end of file diff --git a/tests/unit/src/unit/TestOverloads.hx b/tests/unit/src/unit/TestOverloads.hx index 72d0db0ca6e..59e3161a5f7 100644 --- a/tests/unit/src/unit/TestOverloads.hx +++ b/tests/unit/src/unit/TestOverloads.hx @@ -2,6 +2,7 @@ package unit; import haxe.io.Bytes; import unit.HelperMacros.typeError; import unit.HelperMacros.typedAs; + using unit.TestOverloads.UsingTest2; using unit.TestOverloads.UsingTest3; From fa1b899070640e09c9781d2cdb660eff785e3379 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Tue, 2 Jan 2024 10:28:37 +0100 Subject: [PATCH 063/184] [server] turn warnings into CBOs --- src/compiler/server.ml | 4 +++- src/context/common.ml | 4 ++++ src/context/display/deprecationCheck.ml | 9 ++++++--- src/context/typecore.ml | 7 ++++++- src/core/tFunctions.ml | 4 ++-- src/core/tType.ml | 7 ++++--- src/macro/macroApi.ml | 4 ++-- src/typing/finalization.ml | 2 +- src/typing/typeloadFields.ml | 2 +- src/typing/typeloadModule.ml | 6 +++--- src/typing/typer.ml | 2 +- 11 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/compiler/server.ml b/src/compiler/server.ml index 48da21090f7..d911e4b2d59 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -396,11 +396,13 @@ let check_module sctx ctx m p = state let handle_cache_bound_objects com cbol = - List.iter (function + DynArray.iter (function | Resource(name,data) -> Hashtbl.replace com.resources name data | IncludeFile(file,position) -> com.include_files <- (file,position) :: com.include_files + | Warning(w,msg,p) -> + com.warning w [] msg p ) cbol (* Adds module [m] and all its dependencies (recursively) from the cache to the current compilation diff --git a/src/context/common.ml b/src/context/common.ml index 2a94ab7c79a..bfa4cf68504 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -421,6 +421,10 @@ let ignore_error com = if b then com.has_error <- true; b +let module_warning com m w options msg p = + DynArray.add m.m_extra.m_cache_bound_objects (Warning(w,msg,p)); + com.warning w options msg p + (* Defines *) module Define = Define diff --git a/src/context/display/deprecationCheck.ml b/src/context/display/deprecationCheck.ml index db6ee557c60..947da06e055 100644 --- a/src/context/display/deprecationCheck.ml +++ b/src/context/display/deprecationCheck.ml @@ -7,12 +7,14 @@ type deprecation_context = { com : Common.context; class_meta : metadata_entry list; field_meta : metadata_entry list; + curmod : module_def; } let create_context com = { com = com; class_meta = []; field_meta = []; + curmod = null_module; } let warned_positions = Hashtbl.create 0 @@ -23,7 +25,7 @@ let warn_deprecation dctx s p_usage = Hashtbl.add warned_positions (pkey p_usage) (s,p_usage); if not (is_diagnostics dctx.com) then begin let options = Warning.from_meta (dctx.class_meta @ dctx.field_meta) in - dctx.com.warning WDeprecated options s p_usage; + module_warning dctx.com dctx.curmod WDeprecated options s p_usage; end end @@ -103,7 +105,7 @@ let run com = let dctx = create_context com in List.iter (fun t -> match t with | TClassDecl c when not (Meta.has Meta.Deprecated c.cl_meta) -> - let dctx = {dctx with class_meta = c.cl_meta} in + let dctx = {dctx with class_meta = c.cl_meta; curmod = c.cl_module} in (match c.cl_constructor with None -> () | Some cf -> run_on_field dctx cf); (match c.cl_init with None -> () | Some e -> run_on_expr dctx e); List.iter (run_on_field dctx) c.cl_ordered_statics; @@ -112,11 +114,12 @@ let run com = () ) com.types -let check_is com cl_meta cf_meta name meta p = +let check_is com m cl_meta cf_meta name meta p = let dctx = { com = com; class_meta = cl_meta; field_meta = cf_meta; + curmod = m; } in if is_next dctx.com && name = "is" && not (Meta.has Meta.Deprecated meta) then warn_deprecation dctx "Using \"is\" as an identifier is deprecated" p \ No newline at end of file diff --git a/src/context/typecore.ml b/src/context/typecore.ml index 87904211ae5..3cb6f859a2c 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -241,7 +241,11 @@ let pass_name = function let warning ?(depth=0) ctx w msg p = let options = (Warning.from_meta ctx.curclass.cl_meta) @ (Warning.from_meta ctx.curfield.cf_meta) in - ctx.com.warning ~depth w options msg p + match Warning.get_mode w options with + | WMEnable -> + module_warning ctx.com ctx.m.curmod w options msg p + | WMDisable -> + () let make_call ctx e el t p = (!make_call_ref) ctx e el t p @@ -751,6 +755,7 @@ let create_deprecation_context ctx = { (DeprecationCheck.create_context ctx.com) with class_meta = ctx.curclass.cl_meta; field_meta = ctx.curfield.cf_meta; + curmod = ctx.m.curmod; } (* -------------- debug functions to activate when debugging typer passes ------------------------------- *) diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index bbcb8a2db60..43aa9f5b26f 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -166,7 +166,7 @@ let module_extra file sign time kind policy = m_processed = 0; m_deps = PMap.empty; m_kind = kind; - m_cache_bound_objects = []; + m_cache_bound_objects = DynArray.create (); m_if_feature = []; m_features = Hashtbl.create 0; m_check_policy = policy; @@ -203,7 +203,7 @@ let null_module = { m_path = [] , ""; m_types = []; m_statics = None; - m_extra = module_extra "" "" 0. MFake []; + m_extra = module_extra "" (Digest.string "") 0. MFake 0 []; } let null_class = diff --git a/src/core/tType.ml b/src/core/tType.ml index d601575c77e..2ae0c85886b 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -60,6 +60,7 @@ type type_param_host = type cache_bound_object = | Resource of string * string | IncludeFile of string * string + | Warning of WarningList.warning * string * pos type t = | TMono of tmono @@ -402,7 +403,7 @@ and module_def_display = { and module_def_extra = { m_file : Path.UniqueKey.lazy_t; - m_sign : string; + m_sign : Digest.t; m_display : module_def_display; mutable m_check_policy : module_check_policy list; mutable m_time : float; @@ -410,9 +411,9 @@ and module_def_extra = { mutable m_added : int; mutable m_checked : int; mutable m_processed : int; - mutable m_deps : (int,(string (* sign *) * path)) PMap.t; + mutable m_deps : (int,(Digest.t (* sign *) * path)) PMap.t; mutable m_kind : module_kind; - mutable m_cache_bound_objects : cache_bound_object list; + mutable m_cache_bound_objects : cache_bound_object DynArray.t; mutable m_if_feature : (string * class_field_ref) list; mutable m_features : (string,bool) Hashtbl.t; } diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index 952241ee0ba..4b49dc2150d 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -2088,7 +2088,7 @@ let macro_api ccom get_api = if name = "" then failwith "Empty resource name"; Hashtbl.replace (ccom()).resources name data; let m = (get_api()).current_module() in - m.m_extra.m_cache_bound_objects <- (Resource(name,data)) :: m.m_extra.m_cache_bound_objects; + DynArray.add m.m_extra.m_cache_bound_objects (Resource(name,data)); vnull ); "get_resources", vfun0 (fun() -> @@ -2302,7 +2302,7 @@ let macro_api ccom get_api = in (ccom()).include_files <- (file, position) :: (ccom()).include_files; let m = (get_api()).current_module() in - m.m_extra.m_cache_bound_objects <- (IncludeFile(file,position)) :: m.m_extra.m_cache_bound_objects; + DynArray.add m.m_extra.m_cache_bound_objects (IncludeFile(file,position)); vnull ); (* Compilation server *) diff --git a/src/typing/finalization.ml b/src/typing/finalization.ml index 72b0847b5d0..8f27c9de0df 100644 --- a/src/typing/finalization.ml +++ b/src/typing/finalization.ml @@ -112,7 +112,7 @@ let sort_types com (modules : module_lut) = match state p with | Done -> () | Generating -> - com.warning WStaticInitOrder [] ("Warning : maybe loop in static generation of " ^ s_type_path p) (t_infos t).mt_pos; + module_warning com (t_infos t).mt_module WStaticInitOrder [] ("Warning : maybe loop in static generation of " ^ s_type_path p) (t_infos t).mt_pos; | NotYet -> Hashtbl.add states p Generating; let t = (match t with diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index f8a45c83c9d..9651bd3618b 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -638,7 +638,7 @@ let create_field_context ctx cctx cff is_display_file display_modifier = fctx let create_typer_context_for_field ctx cctx fctx cff = - DeprecationCheck.check_is ctx.com ctx.curclass.cl_meta cff.cff_meta (fst cff.cff_name) cff.cff_meta (snd cff.cff_name); + DeprecationCheck.check_is ctx.com ctx.m.curmod ctx.curclass.cl_meta cff.cff_meta (fst cff.cff_name) cff.cff_meta (snd cff.cff_name); let ctx = { ctx with pass = PBuildClass; (* will be set later to PTypeExpr *) diff --git a/src/typing/typeloadModule.ml b/src/typing/typeloadModule.ml index 626d60b69db..8e6e182de34 100644 --- a/src/typing/typeloadModule.ml +++ b/src/typing/typeloadModule.ml @@ -65,7 +65,7 @@ module ModuleLevel = struct let decls = ref [] in let statics = ref [] in let check_name name meta also_statics p = - DeprecationCheck.check_is com meta [] name meta p; + DeprecationCheck.check_is com ctx.m.curmod meta [] name meta p; let error prev_pos = display_error ctx.com ("Name " ^ name ^ " is already defined in this module") p; raise_typing_error ~depth:1 (compl_msg "Previous declaration here") prev_pos; @@ -195,7 +195,7 @@ module ModuleLevel = struct | None -> () | Some p -> let options = Warning.from_meta d.d_meta in - ctx.com.warning WDeprecatedEnumAbstract options "`@:enum abstract` is deprecated in favor of `enum abstract`" p + module_warning ctx.com ctx.m.curmod WDeprecatedEnumAbstract options "`@:enum abstract` is deprecated in favor of `enum abstract`" p end; decls := (TAbstractDecl a, decl) :: !decls; match d.d_data with @@ -378,7 +378,7 @@ module TypeLevel = struct ef_params = params; ef_meta = c.ec_meta; } in - DeprecationCheck.check_is ctx.com e.e_meta f.ef_meta f.ef_name f.ef_meta f.ef_name_pos; + DeprecationCheck.check_is ctx.com ctx.m.curmod e.e_meta f.ef_meta f.ef_name f.ef_meta f.ef_name_pos; let cf = class_field_of_enum_field f in if ctx.is_display_file && DisplayPosition.display_position#enclosed_in f.ef_name_pos then DisplayEmitter.display_enum_field ctx e f p; diff --git a/src/typing/typer.ml b/src/typing/typer.ml index 5eced0b8b64..ef95b897573 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -707,7 +707,7 @@ and type_vars ctx vl p = let vl = List.map (fun ev -> let n = fst ev.ev_name and pv = snd ev.ev_name in - DeprecationCheck.check_is ctx.com ctx.curclass.cl_meta ctx.curfield.cf_meta n ev.ev_meta pv; + DeprecationCheck.check_is ctx.com ctx.m.curmod ctx.curclass.cl_meta ctx.curfield.cf_meta n ev.ev_meta pv; try let t = Typeload.load_type_hint ctx p ev.ev_type in let e = (match ev.ev_expr with From 57d2a3f5604260c983836fa020eb2c7a10cf75cd Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Tue, 2 Jan 2024 10:31:39 +0100 Subject: [PATCH 064/184] [server] set the current m_added when creating m_extra --- src/codegen/gencommon/gencommon.ml | 4 ++-- src/context/typecore.ml | 2 +- src/core/tFunctions.ml | 4 ++-- src/typing/generic.ml | 4 ++-- src/typing/typeloadModule.ml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/codegen/gencommon/gencommon.ml b/src/codegen/gencommon/gencommon.ml index d087d44ac3f..5324ae9c0f6 100644 --- a/src/codegen/gencommon/gencommon.ml +++ b/src/codegen/gencommon/gencommon.ml @@ -626,11 +626,11 @@ let new_ctx con = gadd_type = (fun md should_filter -> if should_filter then begin gen.gtypes_list <- md :: gen.gtypes_list; - gen.gmodules <- { m_id = alloc_mid(); m_path = (t_path md); m_types = [md]; m_statics = None; m_extra = module_extra "" "" 0. MFake [] } :: gen.gmodules; + gen.gmodules <- { m_id = alloc_mid(); m_path = (t_path md); m_types = [md]; m_statics = None; m_extra = module_extra "" "" 0. MFake gen.gcon.compilation_step [] } :: gen.gmodules; Hashtbl.add gen.gtypes (t_path md) md; end else gen.gafter_filters_ended <- (fun () -> gen.gtypes_list <- md :: gen.gtypes_list; - gen.gmodules <- { m_id = alloc_mid(); m_path = (t_path md); m_types = [md]; m_statics = None; m_extra = module_extra "" "" 0. MFake [] } :: gen.gmodules; + gen.gmodules <- { m_id = alloc_mid(); m_path = (t_path md); m_types = [md]; m_statics = None; m_extra = module_extra "" "" 0. MFake gen.gcon.compilation_step [] } :: gen.gmodules; Hashtbl.add gen.gtypes (t_path md) md; ) :: gen.gafter_filters_ended; ); diff --git a/src/context/typecore.ml b/src/context/typecore.ml index 3cb6f859a2c..4560788cde2 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -480,7 +480,7 @@ let create_fake_module ctx file = m_path = (["$DEP"],file); m_types = []; m_statics = None; - m_extra = module_extra file (Define.get_signature ctx.com.defines) (file_time file) MFake []; + m_extra = module_extra file (Define.get_signature ctx.com.defines) (file_time file) MFake ctx.com.compilation_step []; } in Hashtbl.add fake_modules key mdep; mdep diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index 43aa9f5b26f..d707c936f23 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -150,7 +150,7 @@ let mk_typedef m path pos name_pos t = t_restore = (fun () -> ()); } -let module_extra file sign time kind policy = +let module_extra file sign time kind added policy = { m_file = Path.UniqueKey.create_lazy file; m_sign = sign; @@ -160,7 +160,7 @@ let module_extra file sign time kind policy = m_import_positions = PMap.empty; }; m_cache_state = MSGood; - m_added = 0; + m_added = added; m_checked = 0; m_time = time; m_processed = 0; diff --git a/src/typing/generic.ml b/src/typing/generic.ml index a1e3fc7e411..2c34510de40 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -181,7 +181,7 @@ let static_method_container gctx c cf p = m_path = (pack,name); m_types = []; m_statics = None; - m_extra = module_extra (s_type_path (pack,name)) m.m_extra.m_sign 0. MFake m.m_extra.m_check_policy; + m_extra = module_extra (s_type_path (pack,name)) m.m_extra.m_sign 0. MFake gctx.ctx.com.compilation_step m.m_extra.m_check_policy; } in gctx.mg <- Some mg; let cg = mk_class mg (pack,name) c.cl_pos c.cl_name_pos in @@ -282,7 +282,7 @@ let build_generic_class ctx c p tl = m_path = (pack,name); m_types = []; m_statics = None; - m_extra = module_extra (s_type_path (pack,name)) m.m_extra.m_sign 0. MFake m.m_extra.m_check_policy; + m_extra = module_extra (s_type_path (pack,name)) m.m_extra.m_sign 0. MFake gctx.ctx.com.compilation_step m.m_extra.m_check_policy; } in gctx.mg <- Some mg; let cg = mk_class mg (pack,name) c.cl_pos c.cl_name_pos in diff --git a/src/typing/typeloadModule.ml b/src/typing/typeloadModule.ml index 8e6e182de34..e447f4721d8 100644 --- a/src/typing/typeloadModule.ml +++ b/src/typing/typeloadModule.ml @@ -50,7 +50,7 @@ module ModuleLevel = struct m_path = mpath; m_types = []; m_statics = None; - m_extra = module_extra (Path.get_full_path file) (Define.get_signature ctx.com.defines) (file_time file) (if ctx.com.is_macro_context then MMacro else MCode) (get_policy ctx.g mpath); + m_extra = module_extra (Path.get_full_path file) (Define.get_signature ctx.com.defines) (file_time file) (if ctx.com.is_macro_context then MMacro else MCode) ctx.com.compilation_step (get_policy ctx.g mpath); } in m From 03db008d5e6f4dfd210c24360251f7153ebf233e Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Tue, 2 Jan 2024 10:33:40 +0100 Subject: [PATCH 065/184] [typer] pull some random changes from hxb branch --- src/context/common.ml | 4 ++-- src/core/globals.ml | 10 ++++++++-- src/core/tFunctions.ml | 17 +++++++++++++++++ src/core/tPrinting.ml | 7 ++++--- src/optimization/dce.ml | 9 --------- src/typing/typeloadModule.ml | 2 +- 6 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/context/common.ml b/src/context/common.ml index bfa4cf68504..9dfdba92ff6 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -1115,7 +1115,7 @@ let cache_directory ctx class_path dir f_dir = in Option.may (Array.iter prepare_file) dir_listing -let find_file ctx f = +let find_file ctx ?(class_path=ctx.class_path) f = try match ctx.file_lookup_cache#find f with | None -> raise Exit @@ -1150,7 +1150,7 @@ let find_file ctx f = loop (had_empty || p = "") l end in - let r = try Some (loop false ctx.class_path) with Not_found -> None in + let r = try Some (loop false class_path) with Not_found -> None in ctx.file_lookup_cache#add f r; match r with | None -> raise Not_found diff --git a/src/core/globals.ml b/src/core/globals.ml index be184e3ecff..e7a834787cb 100644 --- a/src/core/globals.ml +++ b/src/core/globals.ml @@ -171,8 +171,14 @@ let die ?p msg ml_loc = in let ver = s_version_full and os_type = if Sys.unix then "unix" else "windows" in - Printf.eprintf "%s\nHaxe: %s; OS type: %s;\n%s\n%s" msg ver os_type ml_loc backtrace; - assert false + let s = Printf.sprintf "%s\nHaxe: %s; OS type: %s;\n%s\n%s" msg ver os_type ml_loc backtrace in + failwith s + +let dump_callstack () = + print_endline (Printexc.raw_backtrace_to_string (Printexc.get_callstack 200)) + +let dump_backtrace () = + print_endline (Printexc.raw_backtrace_to_string (Printexc.get_raw_backtrace ())) module MessageSeverity = struct type t = diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index d707c936f23..247970f5428 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -198,6 +198,15 @@ let mk_field name ?(public = true) ?(static = false) t p name_pos = { ); } +let find_field c name kind = + match kind with + | CfrConstructor -> + begin match c.cl_constructor with Some cf -> cf | None -> raise Not_found end + | CfrStatic -> + PMap.find name c.cl_statics + | CfrMember -> + PMap.find name c.cl_fields + let null_module = { m_id = alloc_mid(); m_path = [] , ""; @@ -598,6 +607,14 @@ let rec follow_without_type t = follow_without_type t | _ -> t +let rec follow_lazy_and_mono t = match t with + | TMono {tm_type = Some t} -> + follow_lazy_and_mono t + | TLazy f -> + follow_lazy_and_mono (lazy_type f) + | _ -> + t + let rec ambiguate_funs t = match follow t with | TFun _ -> TFun ([], t_dynamic) diff --git a/src/core/tPrinting.ml b/src/core/tPrinting.ml index 6361b497d0a..5ac61c1d827 100644 --- a/src/core/tPrinting.ml +++ b/src/core/tPrinting.ml @@ -139,7 +139,7 @@ let s_type_param s_type ttp = | Some t -> Printf.sprintf "%s = %s" s (s_type t) end - + let s_access is_read = function | AccNormal -> "default" | AccNo -> "null" @@ -460,7 +460,7 @@ module Printer = struct | TPHEnumConstructor -> "TPHEnumConstructor" | TPHAnonField -> "TPHAnonField" | TPHLocal -> "TPHLocal" - + let s_type_param tabs ttp = s_record_fields tabs [ "name",ttp.ttp_name; @@ -477,7 +477,7 @@ module Printer = struct let s_tclass_field_flags flags = s_flags flags flag_tclass_field_names - let s_tclass_field tabs cf = + let rec s_tclass_field tabs cf = s_record_fields tabs [ "cf_name",cf.cf_name; "cf_doc",s_doc cf.cf_doc; @@ -489,6 +489,7 @@ module Printer = struct "cf_params",s_type_params (tabs ^ "\t") cf.cf_params; "cf_expr",s_opt (s_expr_ast true "\t\t" s_type) cf.cf_expr; "cf_flags",s_tclass_field_flags cf.cf_flags; + "cf_overloads",s_list "\n" (s_tclass_field (tabs ^ "\t")) cf.cf_overloads ] let s_tclass tabs c = diff --git a/src/optimization/dce.ml b/src/optimization/dce.ml index 0d1a4970899..03d3ba6a4c9 100644 --- a/src/optimization/dce.ml +++ b/src/optimization/dce.ml @@ -50,15 +50,6 @@ let push_class dce c = dce.curclass <- old ) -let find_field c name kind = - match kind with - | CfrConstructor -> - begin match c.cl_constructor with Some cf -> cf | None -> raise Not_found end - | CfrStatic -> - PMap.find name c.cl_statics - | CfrMember -> - PMap.find name c.cl_fields - let resolve_class_field_ref ctx cfr = let ctx = if cfr.cfr_is_macro && not ctx.is_macro_context then Option.get (ctx.get_macros()) else ctx in let m = ctx.module_lut#find_by_type cfr.cfr_path in diff --git a/src/typing/typeloadModule.ml b/src/typing/typeloadModule.ml index e447f4721d8..014eec7787c 100644 --- a/src/typing/typeloadModule.ml +++ b/src/typing/typeloadModule.ml @@ -573,7 +573,7 @@ module TypeLevel = struct | TMono r -> (match r.tm_type with | None -> Monomorph.bind r tt; - | Some _ -> die "" __LOC__); + | Some t' -> die (Printf.sprintf "typedef %s is already initialized to %s, but new init to %s was attempted" (s_type_path t.t_path) (s_type_kind t') (s_type_kind tt)) __LOC__); | _ -> die "" __LOC__); TypeloadFields.build_module_def ctx (TTypeDecl t) t.t_meta (fun _ -> []) (fun _ -> ()); if ctx.com.platform = Cs && t.t_meta <> [] then From 122ea09563d024ea4ffc005d82c50fa86d53f639 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Tue, 2 Jan 2024 10:35:29 +0100 Subject: [PATCH 066/184] [typer] change how we initialize basic types --- src/context/common.ml | 18 +++++++++++------- src/typing/typerEntry.ml | 23 ++++++++++++++++++----- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/context/common.ml b/src/context/common.ml index 9dfdba92ff6..8f6f5bb4ac3 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -781,7 +781,6 @@ let get_config com = let memory_marker = [|Unix.time()|] let create compilation_step cs version args display_mode = - let m = Type.mk_mono() in let rec com = { compilation_step = compilation_step; cs = cs; @@ -848,12 +847,12 @@ let create compilation_step cs version args display_mode = filter_messages = (fun _ -> ()); pass_debug_messages = DynArray.create(); basic = { - tvoid = m; - tint = m; - tfloat = m; - tbool = m; + tvoid = mk_mono(); + tint = mk_mono(); + tfloat = mk_mono(); + tbool = mk_mono(); + tstring = mk_mono(); tnull = (fun _ -> die "Could use locate abstract Null (was it redefined?)" __LOC__); - tstring = m; tarray = (fun _ -> die "Could not locate class Array (was it redefined?)" __LOC__); }; file_lookup_cache = new hashtbl_lookup; @@ -889,7 +888,12 @@ let clone com is_macro_context = let t = com.basic in { com with cache = None; - basic = { t with tvoid = t.tvoid }; + basic = { t with + tint = mk_mono(); + tfloat = mk_mono(); + tbool = mk_mono(); + tstring = mk_mono(); + }; main_class = None; features = Hashtbl.create 0; callbacks = new compiler_callbacks; diff --git a/src/typing/typerEntry.ml b/src/typing/typerEntry.ml index ff302b2e0c2..6c90f4fb0a9 100644 --- a/src/typing/typerEntry.ml +++ b/src/typing/typerEntry.ml @@ -92,10 +92,20 @@ let create com macros = | TAbstractDecl a -> (match snd a.a_path with | "Void" -> ctx.t.tvoid <- TAbstract (a,[]); - | "Float" -> ctx.t.tfloat <- TAbstract (a,[]); - | "Int" -> ctx.t.tint <- TAbstract (a,[]) - | "Bool" -> ctx.t.tbool <- TAbstract (a,[]) - | "Dynamic" -> t_dynamic_def := TAbstract(a,extract_param_types a.a_params); + | "Float" -> + let t = (TAbstract (a,[])) in + Type.unify t ctx.t.tfloat; + ctx.t.tfloat <- t + | "Int" -> + let t = (TAbstract (a,[])) in + Type.unify t ctx.t.tint; + ctx.t.tint <- t + | "Bool" -> + let t = (TAbstract (a,[])) in + Type.unify t ctx.t.tbool; + ctx.t.tbool <- t + | "Dynamic" -> + t_dynamic_def := TAbstract(a,extract_param_types a.a_params); | "Null" -> let mk_null t = try @@ -117,7 +127,10 @@ let create com macros = ) ctx.g.std_types.m_types; let m = TypeloadModule.load_module ctx ([],"String") null_pos in List.iter (fun mt -> match mt with - | TClassDecl c -> ctx.t.tstring <- TInst (c,[]) + | TClassDecl c -> + let t = (TInst (c,[])) in + Type.unify t ctx.t.tstring; + ctx.t.tstring <- t | _ -> () ) m.m_types; let m = TypeloadModule.load_module ctx ([],"Std") null_pos in From c9e9459b6e9e9f42aa025fe03d46706064f01863 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 3 Jan 2024 08:31:15 +0100 Subject: [PATCH 067/184] [server] don't merge output lines (#11459) --- src/compiler/server.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/server.ml b/src/compiler/server.ml index d911e4b2d59..ac6fc9aca88 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -124,7 +124,7 @@ module Communication = struct let create_pipe sctx write = let rec self = { write_out = (fun s -> - write ("\x01" ^ String.concat "\x01" (ExtString.String.nsplit s "\n") ^ "\n") + write ("\x01" ^ String.concat "\n\x01" (ExtString.String.nsplit s "\n") ^ "\n") ); write_err = (fun s -> write s From f8d1caf7698c52dbae1fc4eecb67b9a5736001e1 Mon Sep 17 00:00:00 2001 From: Rudy Ges Date: Wed, 3 Jan 2024 11:35:51 +0100 Subject: [PATCH 068/184] [tests] Compilation server vs defineModule/defineType (#11159) * [tests] server tests - basic support for @:variant * [tests] add server test for compilation server safe type building * [tests] server tests - error handling for @:variant * [tests] add debug info * [tests] temp change of build params * [tests] add more debug data * [tests] better debug data on failures * [tests] reenable other server tests --- tests/server/src/cases/CsSafeTypeBuilding.hx | 149 ++++++++++++++++++ .../src/utils/macro/TestBuilder.macro.hx | 125 +++++++++++---- .../test/templates/csSafeTypeBuilding/Bar.hx | 6 + .../test/templates/csSafeTypeBuilding/Baz.hx | 7 + .../test/templates/csSafeTypeBuilding/Foo.hx | 2 + .../csSafeTypeBuilding/Macro.macro.hx | 63 ++++++++ .../test/templates/csSafeTypeBuilding/Main.hx | 9 ++ 7 files changed, 333 insertions(+), 28 deletions(-) create mode 100644 tests/server/src/cases/CsSafeTypeBuilding.hx create mode 100644 tests/server/test/templates/csSafeTypeBuilding/Bar.hx create mode 100644 tests/server/test/templates/csSafeTypeBuilding/Baz.hx create mode 100644 tests/server/test/templates/csSafeTypeBuilding/Foo.hx create mode 100644 tests/server/test/templates/csSafeTypeBuilding/Macro.macro.hx create mode 100644 tests/server/test/templates/csSafeTypeBuilding/Main.hx diff --git a/tests/server/src/cases/CsSafeTypeBuilding.hx b/tests/server/src/cases/CsSafeTypeBuilding.hx new file mode 100644 index 00000000000..f8e15f96642 --- /dev/null +++ b/tests/server/src/cases/CsSafeTypeBuilding.hx @@ -0,0 +1,149 @@ +package cases; + +import haxe.display.Display; +import haxe.display.FsPath; +import haxe.display.Server; +import utest.Assert; + +using StringTools; +using Lambda; + +class CsSafeTypeBuilding extends TestCase { + var originalContent:String; + + override public function setup(async:utest.Async) { + super.setup(async); + + originalContent = ""; + vfs.putContent("Bar.hx", getTemplate("csSafeTypeBuilding/Bar.hx")); + vfs.putContent("Baz.hx", getTemplate("csSafeTypeBuilding/Baz.hx")); + vfs.putContent("Foo.hx", getTemplate("csSafeTypeBuilding/Foo.hx")); + vfs.putContent("Macro.macro.hx", getTemplate("csSafeTypeBuilding/Macro.macro.hx")); + vfs.putContent("Main.hx", getTemplate("csSafeTypeBuilding/Main.hx")); + } + + #if debug + var failed:Bool; + function _assertHasPrint(s:String, ?pos:haxe.PosInfos) { + if (!assertHasPrint(s)) { + failed = true; + haxe.Log.trace("Fail: doesn't contain \"" + s + "\"", pos); + } + } + #end + + function assertResult(target:String) { + #if debug + failed = false; + var assertHasPrint = _assertHasPrint; + #end + assertSuccess(); + + // Make sure all types are generated + assertHasPrint("[runtime] Hello from Bar"); + assertHasPrint("[runtime] Hello from Baz"); + assertHasPrint("[runtime] Hello from Foo__Bar__Bar"); + assertHasPrint("[runtime] Hello from Foo__Baz__Baz"); + assertHasPrint("[runtime] Hello from Foo__Main__Main"); + assertHasPrint("[runtime] Hello from Main"); + + #if debug + if (failed) messages.filter(m -> StringTools.startsWith(m, "Haxe print: ")).iter(m -> trace(m)); + #end + + // Disabled this check because types move around a bit so we get false negatives + // Kept for debugging purposes + if (false && target == "js") { + var content = sys.io.File.getContent(haxe.io.Path.join([testDir, "out.js"])); + Assert.isTrue(content == originalContent); + + // Needs https://github.com/kLabz/hxdiff for displaying diff + // if (content != originalContent) { + // final a = new diff.FileData(haxe.io.Bytes.ofString(originalContent), "expected", Date.now()); + // final b = new diff.FileData(haxe.io.Bytes.ofString(content), "actual", Date.now()); + // var ctx:diff.Context = { + // file1: a, + // file2: b, + // context: 10 + // } + + // final script = diff.Analyze.diff2Files(ctx); + // var diff = diff.Printer.printUnidiff(ctx, script); + // Sys.println(diff); + // } + } + } + + function assertBuilt(modules:Array, ?macroInvalidated:Bool = false) { + #if debug trace('Invalidated ${modules.join(",")} (macro invalidated: ${macroInvalidated ? "true" : "false"})'); #end + #if debug var assertHasPrint = _assertHasPrint; #end + + for (m in modules) { + assertHasPrint('Building $m.'); + + var t = 'Foo__${m}__${m}'; + if (!macroInvalidated) assertHasPrint('[$m] Previously generated type for $t has been discarded.'); + assertHasPrint('[$m] Generating type for $t.'); + + if (m == "Baz") { + assertHasPrint('[$m] Reusing previously generated type for Foo__Bar__Bar.'); + } + } + } + + @:variant("JsDefineModule", true, "js") + @:variant("JsDefineType", false, "js") + @:variant("InterpDefineModule", true, "interp") + @:variant("InterpDefineType", false, "interp") + function test(defineModule:Bool, target:String) { + var targetArgs = switch target { + case "js": ["-js", "out.js", "-lib", "hxnodejs", "-cmd", "node out.js"]; + case "interp": ["--interp"]; + case _: []; + } + + var args = ["-main", "Main", "Baz"]; + if (defineModule) args = args.concat(["-D", "config.defineModule"]); + args = args.concat(targetArgs); + + runHaxe(args); + if (target == "js") originalContent = sys.io.File.getContent(haxe.io.Path.join([testDir, "out.js"])); + assertBuilt(["Main", "Bar", "Baz"], true); + assertResult(target); + + #if debug trace("Rerun without invalidate"); #end + runHaxe(args); + assertResult(target); + + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Baz.hx")}); + runHaxe(args); + assertBuilt(["Baz"]); + assertResult(target); + + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxe(args); + assertBuilt(["Main"]); + assertResult(target); + + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Bar.hx")}); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxe(args); + assertBuilt(["Main", "Bar"]); + assertResult(target); + + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Bar.hx")}); + runHaxe(args); + assertBuilt(["Main", "Bar", "Baz"]); + assertResult(target); + + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Foo.hx")}); + runHaxe(args); + assertBuilt(["Main", "Bar", "Baz"]); + assertResult(target); + + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Macro.macro.hx")}); + runHaxe(args); + assertBuilt(["Main", "Bar", "Baz"], true); + assertResult(target); + } +} diff --git a/tests/server/src/utils/macro/TestBuilder.macro.hx b/tests/server/src/utils/macro/TestBuilder.macro.hx index 1cfab11dea2..d28724d2179 100644 --- a/tests/server/src/utils/macro/TestBuilder.macro.hx +++ b/tests/server/src/utils/macro/TestBuilder.macro.hx @@ -2,11 +2,15 @@ package utils.macro; import haxe.macro.Expr; import haxe.macro.Context; +import haxe.macro.Type; using StringTools; class TestBuilder { static public function build(fields:Array):Array { + var removedFields = []; + var newFields = []; + for (field in fields) { if (!field.name.startsWith("test")) { continue; @@ -16,40 +20,105 @@ class TestBuilder { // Async is already manually handled, nothing to do case FFun(f): - var asyncName = switch f.args { - case []: - var name = "async"; - f.args.push({ - name: name, - type: macro:utest.Async - }); - name; - case [arg]: - if (arg.name == "_") { - arg.name = "async"; - arg.type = macro:utest.Async; + var variants = field.meta.filter(m -> m.name == ":variant"); + if (variants.length == 0) { + makeAsyncTest(f, field.pos); + } else { + // TODO: support functions that define their own async arg (not named `_` or `async`) + var args = f.args.copy(); + f.args = []; + makeAsyncTest(f, field.pos); + + // Ignore original field; generate variants instead + removedFields.push(field); + + for (variant in variants) { + if (variant.params.length == 0) { + Context.error('Unexpected amount of variant parameters.', variant.pos); } - arg.name; - case _: - Context.fatalError('Unexpected amount of test arguments', field.pos); - ""; - } - switch (f.expr.expr) { - case EBlock(el): - var posInfos = Context.getPosInfos(f.expr.pos); - var pos = Context.makePosition({min: posInfos.max, max: posInfos.max, file: posInfos.file}); - el.push(macro @:pos(pos) $i{asyncName}.done()); - f.expr = macro { - $i{asyncName}.setTimeout(20000); - ${transformHaxeCalls(asyncName, el)}; + + var nameParam = variant.params.shift(); + var name:String = try haxe.macro.ExprTools.getValue(nameParam) catch(e) { + Context.error('Variant first parameter should be a String (variant name)', nameParam.pos); + }; + + var inits = [for (arg in args) { + var name = arg.name; + var ct = arg.type; + + if (variant.params.length == 0) { + Context.error('Unexpected amount of variant parameters.', variant.pos); + } + + var param = variant.params.shift(); + macro @:pos(param.pos) var $name:$ct = (($name:$ct) -> $i{name})(${param}); + }]; + + if (variant.params.length > 0) { + Context.error('Unexpected amount of variant parameters.', variant.params[0].pos); } - case _: - Context.error("Block expression expected", f.expr.pos); + + switch (f.expr.expr) { + case EBlock(b): + var ff = { + ret: f.ret, + params: f.params, + expr: {pos: variant.pos, expr: EBlock(inits.concat(b))}, + args: [{name: "async", type: macro:utest.Async}] + }; + + newFields.push({ + pos: variant.pos, + name: field.name + name, + meta: field.meta.filter(m -> m.name != ":variant"), + kind: FFun(ff), + doc: field.doc, + access : field.access + }); + + case _: + } + } } case _: } } - return fields; + + for (f in removedFields) fields.remove(f); + return fields.concat(newFields); + } + + static function makeAsyncTest(f:Function, fpos:Position) { + var asyncName = switch f.args { + case []: + var name = "async"; + f.args.push({ + name: name, + type: macro:utest.Async + }); + name; + case [arg]: + if (arg.name == "_") { + arg.name = "async"; + arg.type = macro:utest.Async; + } + arg.name; + case _: + Context.fatalError('Unexpected amount of test arguments', fpos); + ""; + } + switch (f.expr.expr) { + case EBlock(el): + var posInfos = Context.getPosInfos(f.expr.pos); + var pos = Context.makePosition({min: posInfos.max, max: posInfos.max, file: posInfos.file}); + el.push(macro @:pos(pos) $i{asyncName}.done()); + f.expr = macro { + $i{asyncName}.setTimeout(20000); + ${transformHaxeCalls(asyncName, el)}; + } + case _: + Context.error("Block expression expected", f.expr.pos); + } } static function transformHaxeCalls(asyncName:String, el:Array) { diff --git a/tests/server/test/templates/csSafeTypeBuilding/Bar.hx b/tests/server/test/templates/csSafeTypeBuilding/Bar.hx new file mode 100644 index 00000000000..19434fb20b5 --- /dev/null +++ b/tests/server/test/templates/csSafeTypeBuilding/Bar.hx @@ -0,0 +1,6 @@ +#if !macro @:build(Macro.logBuild()) #end +class Bar { + static function __init__() Sys.println("[runtime] Hello from Bar"); +} + +typedef B = Foo; diff --git a/tests/server/test/templates/csSafeTypeBuilding/Baz.hx b/tests/server/test/templates/csSafeTypeBuilding/Baz.hx new file mode 100644 index 00000000000..574b0c41fa7 --- /dev/null +++ b/tests/server/test/templates/csSafeTypeBuilding/Baz.hx @@ -0,0 +1,7 @@ +#if !macro @:build(Macro.logBuild()) #end +class Baz { + static function __init__() Sys.println("[runtime] Hello from Baz"); +} + +typedef AA = Foo; +typedef BB = Foo; diff --git a/tests/server/test/templates/csSafeTypeBuilding/Foo.hx b/tests/server/test/templates/csSafeTypeBuilding/Foo.hx new file mode 100644 index 00000000000..64cac29e64b --- /dev/null +++ b/tests/server/test/templates/csSafeTypeBuilding/Foo.hx @@ -0,0 +1,2 @@ +#if !macro @:genericBuild(Macro.buildFoo()) #end +class Foo {} diff --git a/tests/server/test/templates/csSafeTypeBuilding/Macro.macro.hx b/tests/server/test/templates/csSafeTypeBuilding/Macro.macro.hx new file mode 100644 index 00000000000..b8a607ab6e1 --- /dev/null +++ b/tests/server/test/templates/csSafeTypeBuilding/Macro.macro.hx @@ -0,0 +1,63 @@ +import haxe.macro.Context; +import haxe.macro.Expr; +import haxe.macro.Type; +import haxe.macro.TypeTools; + +class Macro { + public static function logBuild() { + Sys.println('Building ${Context.getLocalClass().toString()}.'); + return null; + } + + @:persistent static var generated = new Map(); + + static function isAlive(ct:ComplexType, pos:Position):Bool { + // Null check is just there to make it a one liner + // Basically returning true if no exception is caught + return try Context.resolveType(ct, pos) != null catch(e) false; + } + + public static function buildFoo() { + var from = '[${Context.getLocalModule()}] '; + var print = s -> Sys.println(from + s); + + switch (Context.getLocalType()) { + case TInst(_, [target]): + var pos = Context.currentPos(); + var bt = TypeTools.toBaseType(target); + var key = ["Foo", bt.module, bt.name].join("__"); + var ct = TPath({pack: [], name: key}); + + if (generated.exists(key)) { + if (isAlive(ct, pos)) { + print('Reusing previously generated type for $key.'); + return ct; + } + + print('Previously generated type for $key has been discarded.'); + } + + var genDef = macro class $key { + static function __init__() Sys.println("[runtime] Hello from " + $v{key}); + }; + + // Not really needed but nicer + // genDef.pos = pos; + + // Not needed unless dce full + // genDef.meta.push({name: ":keep", params: [], pos: pos}); + + print('Generating type for $key.'); + #if config.defineModule + Context.defineModule(key, [genDef]); + #else + Context.defineType(genDef, bt.module); + #end + + generated.set(key, true); + return ct; + + case _: throw ""; + } + } +} diff --git a/tests/server/test/templates/csSafeTypeBuilding/Main.hx b/tests/server/test/templates/csSafeTypeBuilding/Main.hx new file mode 100644 index 00000000000..108036891c1 --- /dev/null +++ b/tests/server/test/templates/csSafeTypeBuilding/Main.hx @@ -0,0 +1,9 @@ +// Create a dependency to Bar +import Bar; + +typedef A = Foo
; + +#if !macro @:build(Macro.logBuild()) #end +class Main { + static function main() Sys.println("[runtime] Hello from Main"); +} From 8ce18536e763d070c71052fc40f3db5c161d4317 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 3 Jan 2024 14:51:58 +0100 Subject: [PATCH 069/184] [typer] make sure initialization actually picks up String and not any of its deadbeat inline children --- src/typing/typerEntry.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/typing/typerEntry.ml b/src/typing/typerEntry.ml index 6c90f4fb0a9..94f2c315287 100644 --- a/src/typing/typerEntry.ml +++ b/src/typing/typerEntry.ml @@ -127,7 +127,7 @@ let create com macros = ) ctx.g.std_types.m_types; let m = TypeloadModule.load_module ctx ([],"String") null_pos in List.iter (fun mt -> match mt with - | TClassDecl c -> + | TClassDecl ({cl_path = ([],"String")} as c) -> let t = (TInst (c,[])) in Type.unify t ctx.t.tstring; ctx.t.tstring <- t @@ -135,7 +135,7 @@ let create com macros = ) m.m_types; let m = TypeloadModule.load_module ctx ([],"Std") null_pos in List.iter (fun mt -> match mt with - | TClassDecl c -> ctx.g.std <- c; + | TClassDecl ({cl_path = ([],"Std")} as c) -> ctx.g.std <- c; | _ -> () ) m.m_types; let m = TypeloadModule.load_module ctx ([],"Array") null_pos in From e7800f66ed6f4dd904a75879c9de422cccf58883 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 4 Jan 2024 06:06:47 +0100 Subject: [PATCH 070/184] [compiler refactor native lib argument handling slightly --- src/compiler/args.ml | 15 +++++++++------ src/compiler/compilationContext.ml | 18 +++++++++++++++++- src/compiler/compiler.ml | 2 +- src/context/nativeLibraryHandler.ml | 14 ++++++++------ src/macro/macroApi.ml | 10 +++++++++- 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/compiler/args.ml b/src/compiler/args.ml index 48f010f4c04..b275f262f84 100644 --- a/src/compiler/args.ml +++ b/src/compiler/args.ml @@ -66,7 +66,10 @@ let parse_args com = let add_deprecation s = actx.deprecations <- s :: actx.deprecations in - let add_native_lib file extern = actx.native_libs <- (file,extern) :: actx.native_libs in + let add_native_lib file extern kind = + let lib = create_native_lib file extern kind in + actx.native_libs <- lib :: actx.native_libs + in let basic_args_spec = [ ("Target",["--js"],["-js"],Arg.String (set_platform com Js),"","generate JavaScript code into target file"); ("Target",["--lua"],["-lua"],Arg.String (set_platform com Lua),"","generate Lua code into target file"); @@ -206,22 +209,22 @@ let parse_args com = Common.define com Define.FlashStrict ), "","more type strict flash API"); ("Target-specific",["--swf-lib"],["-swf-lib"],Arg.String (fun file -> - add_native_lib file false; + add_native_lib file false SwfLib; ),"","add the SWF library to the compiled SWF"); ("Target-specific",[],["--neko-lib-path"],Arg.String (fun dir -> com.neko_lib_paths <- dir :: com.neko_lib_paths ),"","add the neko library path"); ("Target-specific",["--swf-lib-extern"],["-swf-lib-extern"],Arg.String (fun file -> - add_native_lib file true; + add_native_lib file true SwfLib; ),"","use the SWF library for type checking"); ("Target-specific",["--java-lib"],["-java-lib"],Arg.String (fun file -> - add_native_lib file false; + add_native_lib file false JavaLib; ),"","add an external JAR or directory of JAR files"); ("Target-specific",["--java-lib-extern"],[],Arg.String (fun file -> - add_native_lib file true; + add_native_lib file true JavaLib; ),"","use an external JAR or directory of JAR files for type checking"); ("Target-specific",["--net-lib"],["-net-lib"],Arg.String (fun file -> - add_native_lib file false; + add_native_lib file false NetLib; ),"[@std]","add an external .NET DLL file"); ("Target-specific",["--net-std"],["-net-std"],Arg.String (fun file -> Dotnet.add_net_std com file diff --git a/src/compiler/compilationContext.ml b/src/compiler/compilationContext.ml index 0e18bce18d1..53f99885e1a 100644 --- a/src/compiler/compilationContext.ml +++ b/src/compiler/compilationContext.ml @@ -7,6 +7,17 @@ type server_mode = | SMListen of string | SMConnect of string +type native_lib_kind = + | NetLib + | JavaLib + | SwfLib + +type native_lib_arg = { + lib_file : string; + lib_kind : native_lib_kind; + lib_extern : bool; +} + type arg_context = { mutable classes : Globals.path list; mutable xml_out : string option; @@ -20,7 +31,7 @@ type arg_context = { mutable interp : bool; mutable jvm_flag : bool; mutable swf_version : bool; - mutable native_libs : (string * bool) list; + mutable native_libs : native_lib_arg list; mutable raise_usage : unit -> unit; mutable display_arg : string option; mutable deprecations : string list; @@ -73,3 +84,8 @@ let error_ext ctx (err : Error.error) = error ~depth ~from_macro:err.err_from_macro ctx (Error.error_msg err.err_message) err.err_pos ) err +let create_native_lib file extern kind = { + lib_file = file; + lib_extern = extern; + lib_kind = kind; +} \ No newline at end of file diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index 26860dfe498..9e9b61dc6f8 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -175,7 +175,7 @@ module Setup = struct Common.log com (Buffer.contents buffer); com.callbacks#run com.error_ext com.callbacks#get_before_typer_create; (* Native lib pass 1: Register *) - let fl = List.map (fun (file,extern) -> NativeLibraryHandler.add_native_lib com file extern) (List.rev native_libs) in + let fl = List.map (fun lib -> NativeLibraryHandler.add_native_lib com lib) (List.rev native_libs) in (* Native lib pass 2: Initialize *) List.iter (fun f -> f()) fl; TyperEntry.create com macros diff --git a/src/context/nativeLibraryHandler.ml b/src/context/nativeLibraryHandler.ml index db6837204cc..75e010635a5 100644 --- a/src/context/nativeLibraryHandler.ml +++ b/src/context/nativeLibraryHandler.ml @@ -19,11 +19,15 @@ open Globals open Common +open CompilationContext -let add_native_lib com file is_extern = match com.platform with - | Globals.Flash -> +let add_native_lib com lib = + let file = lib.lib_file in + let is_extern = lib.lib_extern in + match lib.lib_kind with + | SwfLib -> SwfLoader.add_swf_lib com file is_extern - | Globals.Java -> + | JavaLib -> let use_modern = Common.defined com Define.Jvm && not (Common.defined com Define.JarLegacyLoader) in let add file = let std = file = "lib/hxjava-std.jar" in @@ -36,7 +40,7 @@ let add_native_lib com file is_extern = match com.platform with ) (Sys.readdir file)) else add file - | Globals.Cs -> + | NetLib -> let file, is_std = match ExtString.String.nsplit file "@" with | [file] -> file,false @@ -45,5 +49,3 @@ let add_native_lib com file is_extern = match com.platform with | _ -> failwith ("unsupported file@`std` format: " ^ file) in Dotnet.add_net_lib com file is_std is_extern - | pf -> - failwith (Printf.sprintf "Target %s does not support native libraries (trying to load %s)" (platform_name pf) file); \ No newline at end of file diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index 4b49dc2150d..deb6553c1dd 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -2184,7 +2184,15 @@ let macro_api ccom get_api = "add_native_lib", vfun1 (fun file -> let file = decode_string file in let com = ccom() in - NativeLibraryHandler.add_native_lib com file false (); + let open CompilationContext in + let kind = match com.platform with + | Java -> JavaLib + | Cs -> NetLib + | Flash -> SwfLib + | _ -> failwith "Unsupported platform" + in + let lib = create_native_lib file false kind in + NativeLibraryHandler.add_native_lib com lib (); vnull ); "add_native_arg", vfun1 (fun arg -> From adef8b3ec30b5bf250d74cda43c9472ca1df0c4c Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Thu, 4 Jan 2024 12:52:28 +0100 Subject: [PATCH 071/184] [hl] Fix do-while loop in genhl+hlopt (#11461) * [hl] Fix do-while loop in genhl+hlopt * remove can_do --- src/generators/genhl.ml | 5 +---- src/generators/hlopt.ml | 13 ++++++++----- src/optimization/analyzerTexpr.ml | 5 ++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index c378ab4bfbd..b57f56c127d 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -2698,13 +2698,10 @@ and eval_expr ctx e = ctx.m.mbreaks <- []; ctx.m.mcontinues <- []; ctx.m.mloop_trys <- ctx.m.mtrys; - let start = jump ctx (fun p -> OJAlways p) in let continue_pos = current_pos ctx in let ret = jump_back ctx in - let j = jump_expr ctx cond false in - start(); ignore(eval_expr ctx eloop); - set_curpos ctx (max_pos e); + let j = jump_expr ctx cond false in ret(); j(); List.iter (fun f -> f (current_pos ctx)) ctx.m.mbreaks; diff --git a/src/generators/hlopt.ml b/src/generators/hlopt.ml index 5081c31c9f5..79fb79203c0 100644 --- a/src/generators/hlopt.ml +++ b/src/generators/hlopt.ml @@ -947,8 +947,8 @@ let _optimize (f:fundecl) = (* loop : first pass does not recurse, second pass uses cache *) if b2.bloop && b2.bstart < b.bstart then (match b2.bneed_all with None -> acc | Some s -> ISet.union acc s) else ISet.union acc (live b2) - ) ISet.empty b.bnext in - let need_sub = ISet.filter (fun r -> + ) ISet.empty in + let need_sub bl = ISet.filter (fun r -> try let w = PMap.find r b.bwrite in set_live r (w + 1) b.bend; @@ -956,8 +956,8 @@ let _optimize (f:fundecl) = with Not_found -> set_live r b.bstart b.bend; true - ) need_sub in - let need = ISet.union b.bneed need_sub in + ) (need_sub bl) in + let need = ISet.union b.bneed (need_sub b.bnext) in b.bneed_all <- Some need; if b.bloop then begin (* @@ -974,8 +974,11 @@ let _optimize (f:fundecl) = in List.iter (fun b2 -> if b2.bstart > b.bstart then clear b2) b.bprev; List.iter (fun b -> ignore(live b)) b.bnext; + (* do-while loop : recompute self after recompute all next *) + let need = ISet.union b.bneed (need_sub b.bnext) in + b.bneed_all <- Some need; end; - need + Option.get b.bneed_all in ignore(live root); diff --git a/src/optimization/analyzerTexpr.ml b/src/optimization/analyzerTexpr.ml index 7631dfb7293..b5ac00f6c3a 100644 --- a/src/optimization/analyzerTexpr.ml +++ b/src/optimization/analyzerTexpr.ml @@ -1069,12 +1069,11 @@ module Cleanup = struct | TLocal v when IntMap.mem v.v_id !locals -> true | _ -> check_expr references_local e in - let can_do = match com.platform with Hl -> false | _ -> true in let rec loop2 el = match el with - | [{eexpr = TBreak}] when is_true_expr e1 && can_do && not has_continue -> + | [{eexpr = TBreak}] when is_true_expr e1 && not has_continue -> do_while := Some (Texpr.Builder.make_bool com.basic true e1.epos); [] - | [{eexpr = TIf(econd,{eexpr = TBlock[{eexpr = TBreak}]},None)}] when is_true_expr e1 && not (references_local econd) && can_do && not has_continue -> + | [{eexpr = TIf(econd,{eexpr = TBlock[{eexpr = TBreak}]},None)}] when is_true_expr e1 && not (references_local econd) && not has_continue -> do_while := Some econd; [] | {eexpr = TBreak | TContinue | TReturn _ | TThrow _} as e :: el -> From 584a42cb60370b6bf652061e7950603a7500e97e Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 4 Jan 2024 14:28:32 +0100 Subject: [PATCH 072/184] Only set cf_expr_unoptimized if we think we need it (#11462) * [typer] set cf_expr_unoptimized only if we think we need it closes #11460 * use server/invalidate like it's 2024 * actually just delete touchFile so I don't use it again * invalidate more because putContent doesn't do it... This is not a great testing experience I'm having but oh well... --- src-json/warning.json | 5 ++ src/filters/filters.ml | 16 ++++- src/typing/calls.ml | 28 ++++++--- tests/server/src/TestCase.hx | 4 ++ tests/server/src/cases/ServerTests.hx | 58 +++++++++++-------- tests/server/src/cases/issues/Issue11460.hx | 53 +++++++++++++++++ tests/server/src/cases/issues/Issue9358.hx | 2 +- tests/server/src/utils/Vfs.hx | 10 ---- .../test/templates/issues/Issue11460/C.hx | 5 ++ .../test/templates/issues/Issue11460/Main.hx | 3 + 10 files changed, 138 insertions(+), 46 deletions(-) create mode 100644 tests/server/src/cases/issues/Issue11460.hx create mode 100644 tests/server/test/templates/issues/Issue11460/C.hx create mode 100644 tests/server/test/templates/issues/Issue11460/Main.hx diff --git a/src-json/warning.json b/src-json/warning.json index 38a6474deee..54d544f3524 100644 --- a/src-json/warning.json +++ b/src-json/warning.json @@ -98,6 +98,11 @@ "doc": "A type path is being used that is supposed to be reserved on the current target", "parent": "WTyper" }, + { + "name": "WInlineOptimizedField", + "doc": "A cached field which was optimized might lead to different output when inlined", + "parent": "WTyper" + }, { "name": "WPatternMatcher", "doc": "Warnings related to the pattern matcher", diff --git a/src/filters/filters.ml b/src/filters/filters.ml index 0ee097c09ae..0006bd51ca2 100644 --- a/src/filters/filters.ml +++ b/src/filters/filters.ml @@ -708,6 +708,15 @@ let save_class_state com t = a.a_meta <- List.filter (fun (m,_,_) -> m <> Meta.ValueUsed) a.a_meta ) +let might_need_cf_unoptimized c cf = + match cf.cf_kind,c.cl_kind with + | Method MethInline,_ -> + true + | _,KGeneric -> + true + | _ -> + has_class_field_flag cf CfGeneric + let run tctx main before_destruction = let com = tctx.com in let detail_times = (try int_of_string (Common.defined_value_safe com ~default:"0" Define.FilterTimes) with _ -> 0) in @@ -723,8 +732,11 @@ let run tctx main before_destruction = (* Save cf_expr_unoptimized early: We want to inline with the original expression on the next compilation. *) if not cached then begin - let field cf = - cf.cf_expr_unoptimized <- cf.cf_expr + let field cf = match cf.cf_expr,cf.cf_expr_unoptimized with + | Some e,None when might_need_cf_unoptimized cls cf -> + cf.cf_expr_unoptimized <- Some e + | _ -> + () in List.iter field cls.cl_ordered_fields; List.iter field cls.cl_ordered_statics; diff --git a/src/typing/calls.ml b/src/typing/calls.ml index 91a2f2bbab7..2839847ec4a 100644 --- a/src/typing/calls.ml +++ b/src/typing/calls.ml @@ -67,17 +67,27 @@ let make_call ctx e params t ?(force_inline=false) p = ); let params = List.map (Optimizer.reduce_expression ctx) params in let force_inline = is_forced_inline cl f in - (match f.cf_expr_unoptimized,f.cf_expr with - | Some {eexpr = TFunction fd},_ - | None,Some { eexpr = TFunction fd } -> + let inline fd = Inline.type_inline ctx f fd ethis params t config p force_inline + in + begin match f.cf_expr_unoptimized with + | Some {eexpr = TFunction fd} -> + inline fd | _ -> - (* - we can't inline because there is most likely a loop in the typing. - this can be caused by mutually recursive vars/functions, some of them - being inlined or not. In that case simply ignore inlining. - *) - raise Exit) + if has_class_field_flag f CfPostProcessed then + warning ctx WInlineOptimizedField (Printf.sprintf "Inlining of cached field %s might lead to unexpected output" f.cf_name) p; + match f.cf_expr with + | Some ({ eexpr = TFunction fd } as e) -> + f.cf_expr_unoptimized <- Some (e); + inline fd + | _ -> + (* + we can't inline because there is most likely a loop in the typing. + this can be caused by mutually recursive vars/functions, some of them + being inlined or not. In that case simply ignore inlining. + *) + raise Exit + end with Exit -> mk (TCall (e,params)) t p diff --git a/tests/server/src/TestCase.hx b/tests/server/src/TestCase.hx index b4954a08a83..621dd1702bf 100644 --- a/tests/server/src/TestCase.hx +++ b/tests/server/src/TestCase.hx @@ -213,6 +213,10 @@ class TestCase implements ITest { } } + function assertSilence() { + return Assert.isTrue(lastResult.stderr == ""); + } + function assertSuccess(?p:haxe.PosInfos) { return Assert.isTrue(0 == errorMessages.length, p); } diff --git a/tests/server/src/cases/ServerTests.hx b/tests/server/src/cases/ServerTests.hx index 8605bc44ff1..130861863c5 100644 --- a/tests/server/src/cases/ServerTests.hx +++ b/tests/server/src/cases/ServerTests.hx @@ -150,10 +150,9 @@ class ServerTests extends TestCase { vfs.putContent("Other.hx", getTemplate("issues/Issue9134/Other.hx")); var args = ["-main", "Main", "Other"]; - runHaxeJsonCb(args, DisplayMethods.Diagnostics, {fileContents: [ - {file: new FsPath("Other.hx")}, - {file: new FsPath("Main.hx")}, - ]}, res -> { + runHaxeJsonCb(args, DisplayMethods.Diagnostics, { + fileContents: [{file: new FsPath("Other.hx")}, {file: new FsPath("Main.hx")},] + }, res -> { Assert.equals(1, res.length); Assert.equals(1, res[0].diagnostics.length); var arg = res[0].diagnostics[0].args; @@ -164,10 +163,12 @@ class ServerTests extends TestCase { runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Other.hx")}); - runHaxeJsonCb(args, DisplayMethods.Diagnostics, {fileContents: [ - {file: new FsPath("Main.hx"), contents: getTemplate("issues/Issue9134/Main2.hx")}, - {file: new FsPath("Other.hx"), contents: getTemplate("issues/Issue9134/Other2.hx")} - ]}, res -> { + runHaxeJsonCb(args, DisplayMethods.Diagnostics, { + fileContents: [ + {file: new FsPath("Main.hx"), contents: getTemplate("issues/Issue9134/Main2.hx")}, + {file: new FsPath("Other.hx"), contents: getTemplate("issues/Issue9134/Other2.hx")} + ] + }, res -> { Assert.equals(1, res.length); Assert.equals(1, res[0].diagnostics.length); var arg = res[0].diagnostics[0].args; @@ -178,10 +179,12 @@ class ServerTests extends TestCase { runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Other.hx")}); - runHaxeJsonCb(args, DisplayMethods.Diagnostics, {fileContents: [ - {file: new FsPath("Main.hx"), contents: getTemplate("issues/Issue9134/Main.hx")}, - {file: new FsPath("Other.hx"), contents: getTemplate("issues/Issue9134/Other2.hx")} - ]}, res -> { + runHaxeJsonCb(args, DisplayMethods.Diagnostics, { + fileContents: [ + {file: new FsPath("Main.hx"), contents: getTemplate("issues/Issue9134/Main.hx")}, + {file: new FsPath("Other.hx"), contents: getTemplate("issues/Issue9134/Other2.hx")} + ] + }, res -> { Assert.equals(2, res.length); for (i in 0...2) { @@ -206,9 +209,12 @@ class ServerTests extends TestCase { for (result in res) { var file = result.file.toString(); - if (StringTools.endsWith(file, "Main.hx")) hasMain = true; - else if (StringTools.endsWith(file, "Other.hx")) hasOther = true; - else continue; + if (StringTools.endsWith(file, "Main.hx")) + hasMain = true; + else if (StringTools.endsWith(file, "Other.hx")) + hasOther = true; + else + continue; var arg = result.diagnostics[0].args; Assert.equals("Unused variable", (cast arg).description); @@ -427,7 +433,7 @@ class ServerTests extends TestCase { vfs.putContent("haxe/ds/Vector.hx", getTemplate("issues/Issue10986/Vector.hx")); var args = ["-main", "Main", "--jvm", "Main.jar"]; runHaxe(args); - vfs.touchFile("haxe/ds/Vector.hx"); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("haxe/ds/Vector.hx")}); runHaxe(args); assertSuccess(); } @@ -459,16 +465,18 @@ class ServerTests extends TestCase { var transform = Marker.extractMarkers(getTemplate("issues/Issue8368/MyMacro2.macro.hx")); var args = ["-main", "Main", "--macro", "define('whatever')"]; - vfs.putContent( - "MyMacro.macro.hx", - transform.source.substr(0, transform.markers[1]) - + transform.source.substr(transform.markers[2], transform.source.length) - ); + vfs.putContent("MyMacro.macro.hx", + transform.source.substr(0, transform.markers[1]) + transform.source.substr(transform.markers[2], transform.source.length)); runHaxe(args); runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MyMacro.macro.hx")}); - var completionRequest = {file: new FsPath("MyMacro.macro.hx"), contents: transform.source, offset: transform.markers[2], wasAutoTriggered: false}; + var completionRequest = { + file: new FsPath("MyMacro.macro.hx"), + contents: transform.source, + offset: transform.markers[2], + wasAutoTriggered: false + }; runHaxeJson(args, DisplayMethods.Completion, completionRequest); Assert.isTrue(parseCompletion().result.items.length == 23); runHaxeJson(args, DisplayMethods.Completion, completionRequest); @@ -488,8 +496,10 @@ class ServerTests extends TestCase { function runLoop() { runHaxeJson(args, DisplayMethods.Diagnostics, {file: new FsPath("Empty.hx")}, () -> { runHaxe(args.concat(["-D", "compile-only-define"]), () -> { - if (assertSuccess() && ++runs < 20) runLoop(); - else async.done(); + if (assertSuccess() && ++runs < 20) + runLoop(); + else + async.done(); }); }); } diff --git a/tests/server/src/cases/issues/Issue11460.hx b/tests/server/src/cases/issues/Issue11460.hx new file mode 100644 index 00000000000..71cdbc51f9d --- /dev/null +++ b/tests/server/src/cases/issues/Issue11460.hx @@ -0,0 +1,53 @@ +package cases.issues; + +using StringTools; + +class Issue11460 extends TestCase { + function testClass(_) { + var mainContentWithInline = getTemplate("issues/Issue11460/Main.hx"); + var mainContentWithoutInline = mainContentWithInline.replace("inline", ""); + vfs.putContent("Main.hx", mainContentWithInline); + vfs.putContent("C.hx", getTemplate("issues/Issue11460/C.hx")); + var args = ["Main", "--interp"]; + + // initial cache + runHaxe(args); + assertSilence(); + + // touching Main doesn't do anything + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxe(args); + assertSilence(); + + // touching both doesn't do anything + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("C.hx")}); + runHaxe(args); + assertSilence(); + + // removing the inline is fine + vfs.putContent("Main.hx", mainContentWithoutInline); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxe(args); + assertSilence(); + + // adding it back is fine too because C is still cached + vfs.putContent("Main.hx", mainContentWithInline); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxe(args); + assertSilence(); + + // removing the inline and changing C is still fine + vfs.putContent("Main.hx", mainContentWithoutInline); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("C.hx")}); + runHaxe(args); + assertSilence(); + + // but adding it now gives us the warning + vfs.putContent("Main.hx", mainContentWithInline); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxe(args); + utest.Assert.match(~/WInlineOptimizedField/, lastResult.stderr); + } +} diff --git a/tests/server/src/cases/issues/Issue9358.hx b/tests/server/src/cases/issues/Issue9358.hx index 0cef1b5cd83..8e096a446ca 100644 --- a/tests/server/src/cases/issues/Issue9358.hx +++ b/tests/server/src/cases/issues/Issue9358.hx @@ -6,7 +6,7 @@ class Issue9358 extends TestCase { vfs.putContent("StateHandler.hx", getTemplate("issues/Issue9358/StateHandler.hx")); var args = ["-cp", "src", "-m", "Main", "-hl", "hl.hl"]; runHaxe(args); - vfs.touchFile("Main.hx"); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); runHaxe(args); assertSuccess(); } diff --git a/tests/server/src/utils/Vfs.hx b/tests/server/src/utils/Vfs.hx index 3aefc5ecae7..b73678aa4cc 100644 --- a/tests/server/src/utils/Vfs.hx +++ b/tests/server/src/utils/Vfs.hx @@ -17,16 +17,6 @@ class Vfs { FileSystem.createDirectory(physicalPath); } - public function touchFile(path:String) { - var path = getPhysicalPath(path); - FileSystem.createDirectory(path.dir); - var file = Fs.openSync(path.dir + "/" + path.file + "." + path.ext, 'a'); - var last = Fs.fstatSync(file).mtime; - var notNow = last.delta(1000); - Fs.futimesSync(file, notNow, notNow); - Fs.closeSync(file); - } - public function overwriteContent(path:String, content:String) { var path = getPhysicalPath(path).toString(); if (!FileSystem.exists(path)) { diff --git a/tests/server/test/templates/issues/Issue11460/C.hx b/tests/server/test/templates/issues/Issue11460/C.hx new file mode 100644 index 00000000000..0c336cfec11 --- /dev/null +++ b/tests/server/test/templates/issues/Issue11460/C.hx @@ -0,0 +1,5 @@ +class C { + static public function doSomething() { + trace("Ok I did something"); + } +} diff --git a/tests/server/test/templates/issues/Issue11460/Main.hx b/tests/server/test/templates/issues/Issue11460/Main.hx new file mode 100644 index 00000000000..84ba0c6639b --- /dev/null +++ b/tests/server/test/templates/issues/Issue11460/Main.hx @@ -0,0 +1,3 @@ +function main() { + inline C.doSomething(); +} From 29085f86c837d94d89a85d95d952d7a9c6fbc2ca Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Sun, 7 Jan 2024 10:30:41 +0100 Subject: [PATCH 073/184] [opam] bump camlp5 version to 8.00.03 because that works with OCaml 4.14 --- haxe.opam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haxe.opam b/haxe.opam index e93455e01f1..6b8d4f8d8f1 100644 --- a/haxe.opam +++ b/haxe.opam @@ -20,7 +20,7 @@ install: [make "install" "INSTALL_DIR=%{prefix}%"] remove: [make "uninstall" "INSTALL_DIR=%{prefix}%"] depends: [ ("ocaml" {>= "5.0"} & ("camlp5" {build})) - | ("ocaml" {>= "4.08" & < "5.0"} & ("camlp5" {build & = "8.00"})) + | ("ocaml" {>= "4.08" & < "5.0"} & ("camlp5" {build & = "8.00.03"})) "ocamlfind" {build} "dune" {>= "1.11"} "sedlex" {>= "2.0"} From 938aaa95f0854b259180d97e414c4197c656ab7c Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Sun, 7 Jan 2024 21:17:05 +0100 Subject: [PATCH 074/184] [filters] recurse into expressions of local statics closes #11469 --- src/filters/localStatic.ml | 51 +++++++++++++++++------- tests/unit/src/unit/issues/Issue11469.hx | 9 +++++ 2 files changed, 46 insertions(+), 14 deletions(-) create mode 100644 tests/unit/src/unit/issues/Issue11469.hx diff --git a/src/filters/localStatic.ml b/src/filters/localStatic.ml index 50b5d759c8d..b6d9c1d7d5f 100644 --- a/src/filters/localStatic.ml +++ b/src/filters/localStatic.ml @@ -3,11 +3,18 @@ open Type open Typecore open Error -let promote_local_static ctx lut v eo = - let name = Printf.sprintf "%s_%s" ctx.curfield.cf_name v.v_name in +type lscontext = { + ctx : typer; + lut : (int,tclass_field) Hashtbl.t; + mutable added_fields : tclass_field list; +} + +let promote_local_static lsctx run v eo = + let name = Printf.sprintf "%s_%s" lsctx.ctx.curfield.cf_name v.v_name in + let c = lsctx.ctx.curclass in begin try - let cf = PMap.find name ctx.curclass.cl_statics in - display_error ctx.com (Printf.sprintf "The expanded name of this local (%s) conflicts with another static field" name) v.v_pos; + let cf = PMap.find name c.cl_statics in + display_error lsctx.ctx.com (Printf.sprintf "The expanded name of this local (%s) conflicts with another static field" name) v.v_pos; raise_typing_error ~depth:1 "Conflicting field was found here" cf.cf_name_pos; with Not_found -> let cf = mk_field name ~static:true v.v_type v.v_pos v.v_pos in @@ -16,34 +23,45 @@ let promote_local_static ctx lut v eo = | None -> () | Some e -> + let no_local_in_static p = + raise_typing_error "Accessing local variables in static initialization is not allowed" p + in let rec loop e = match e.eexpr with - | TLocal _ | TFunction _ -> - raise_typing_error "Accessing local variables in static initialization is not allowed" e.epos + | TLocal v when has_var_flag v VStatic -> + run e + | TFunction _ | TLocal _ -> + no_local_in_static e.epos | TConst (TThis | TSuper) -> raise_typing_error "Accessing `this` in static initialization is not allowed" e.epos | TReturn _ | TBreak | TContinue -> raise_typing_error "This kind of control flow in static initialization is not allowed" e.epos | _ -> - iter loop e + map_expr loop e in - loop e; + let e = loop e in cf.cf_expr <- Some e end; - TClass.add_field ctx.curclass cf; - Hashtbl.add lut v.v_id cf + lsctx.added_fields <- cf :: lsctx.added_fields; + (* Add to lookup early so that the duplication check works. *) + c.cl_statics <- PMap.add cf.cf_name cf c.cl_statics; + Hashtbl.add lsctx.lut v.v_id cf end let find_local_static lut v = Hashtbl.find lut v.v_id let run ctx e = - let local_static_lut = Hashtbl.create 0 in + let lsctx = { + ctx = ctx; + lut = Hashtbl.create 0; + added_fields = []; + } in let c = ctx.curclass in let rec run e = match e.eexpr with | TBlock el -> let el = ExtList.List.filter_map (fun e -> match e.eexpr with | TVar(v,eo) when has_var_flag v VStatic -> - promote_local_static ctx local_static_lut v eo; + promote_local_static lsctx run v eo; None | _ -> Some (run e) @@ -51,7 +69,7 @@ let run ctx e = { e with eexpr = TBlock el } | TLocal v when has_var_flag v VStatic -> begin try - let cf = find_local_static local_static_lut v in + let cf = find_local_static lsctx.lut v in Texpr.Builder.make_static_field c cf e.epos with Not_found -> raise_typing_error (Printf.sprintf "Could not find local static %s (id %i)" v.v_name v.v_id) e.epos @@ -59,4 +77,9 @@ let run ctx e = | _ -> Type.map_expr run e in - run e + let e = run e in + (* Add to ordered list in reverse order *) + List.iter (fun cf -> + c.cl_ordered_statics <- cf :: c.cl_ordered_statics + ) lsctx.added_fields; + e diff --git a/tests/unit/src/unit/issues/Issue11469.hx b/tests/unit/src/unit/issues/Issue11469.hx new file mode 100644 index 00000000000..783bb17e352 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11469.hx @@ -0,0 +1,9 @@ +package unit.issues; + +class Issue11469 extends Test { + function test() { + static var c = 10; + static var d = c + 1; + eq(11, d); + } +} From 7665333b6c2a2fbcabd60a51d0bef21263822e46 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Mon, 8 Jan 2024 07:19:59 +0100 Subject: [PATCH 075/184] [jvm] fix functional interfaces some more closes #11390 --- src/generators/jvm/jvmFunctions.ml | 30 ++++++---- tests/misc/java/projects/Issue11390/Main.hx | 32 +++++++++++ tests/misc/java/projects/Issue11390/Setup.hx | 6 ++ .../java/projects/Issue11390/compile.hxml | 12 ++++ .../projects/Issue11390/compile.hxml.stdout | 10 ++++ .../Issue11390/project/test/Robot.java | 42 ++++++++++++++ .../Issue11390/project/test/RobotFactory.java | 56 +++++++++++++++++++ 7 files changed, 176 insertions(+), 12 deletions(-) create mode 100644 tests/misc/java/projects/Issue11390/Main.hx create mode 100644 tests/misc/java/projects/Issue11390/Setup.hx create mode 100644 tests/misc/java/projects/Issue11390/compile.hxml create mode 100644 tests/misc/java/projects/Issue11390/compile.hxml.stdout create mode 100644 tests/misc/java/projects/Issue11390/project/test/Robot.java create mode 100644 tests/misc/java/projects/Issue11390/project/test/RobotFactory.java diff --git a/src/generators/jvm/jvmFunctions.ml b/src/generators/jvm/jvmFunctions.ml index dec41deb5ca..1d4058db9f3 100644 --- a/src/generators/jvm/jvmFunctions.ml +++ b/src/generators/jvm/jvmFunctions.ml @@ -317,6 +317,8 @@ module JavaFunctionalInterfaces = struct let unify jfi args ret = let params = ref [] in let rec unify jsig1 jsig2 = match jsig1,jsig2 with + | TObject _,TObject((["java";"lang"],"Object"),[]) -> + true | TObject(path1,params1),TObject(path2,params2) -> path1 = path2 && unify_params params1 params2 @@ -362,7 +364,7 @@ module JavaFunctionalInterfaces = struct | None,None -> loop jfi.jargs args | Some jsig1,Some jsig2 -> - if unify jsig1 jsig2 then loop jfi.jargs args + if unify jsig2 jsig1 then loop jfi.jargs args else None | _ -> None @@ -441,24 +443,28 @@ class typed_function Hashtbl.add implemented_interfaces path true; end in + let spawn_invoke_next name msig is_bridge = + let flags = [MPublic] in + let flags = if is_bridge then MBridge :: MSynthetic :: flags else flags in + jc_closure#spawn_method name msig flags + in let spawn_forward_function meth_from meth_to is_bridge = let msig = method_sig meth_from.dargs meth_from.dret in if not (jc_closure#has_method meth_from.name msig) then begin - let flags = [MPublic] in - let flags = if is_bridge then MBridge :: MSynthetic :: flags else flags in - let jm_invoke_next = jc_closure#spawn_method meth_from.name msig flags in + let jm_invoke_next = spawn_invoke_next meth_from.name msig is_bridge in functions#make_forward_method jc_closure jm_invoke_next meth_from meth_to; end in let check_functional_interfaces meth = - try - let l = JavaFunctionalInterfaces.find_compatible meth.dargs meth.dret functional_interface_filter in - List.iter (fun (jfi,params) -> - add_interface jfi.jpath params; - spawn_forward_function {meth with name=jfi.jname} meth false; - ) l - with Not_found -> - () + let l = JavaFunctionalInterfaces.find_compatible meth.dargs meth.dret functional_interface_filter in + List.iter (fun (jfi,params) -> + add_interface jfi.jpath params; + let msig = method_sig jfi.jargs jfi.jret in + if not (jc_closure#has_method jfi.jname msig) then begin + let jm_invoke_next = spawn_invoke_next jfi.jname msig false in + functions#make_forward_method_jsig jc_closure jm_invoke_next meth.name jfi.jargs jfi.jret meth.dargs meth.dret + end + ) l in let rec loop meth = check_functional_interfaces meth; diff --git a/tests/misc/java/projects/Issue11390/Main.hx b/tests/misc/java/projects/Issue11390/Main.hx new file mode 100644 index 00000000000..202125d1a96 --- /dev/null +++ b/tests/misc/java/projects/Issue11390/Main.hx @@ -0,0 +1,32 @@ +package; + +import test.Robot; +import test.RobotFactory; + +class Main { + public static function main() { + var robot1 = RobotFactory.buildMathRobot(); + var robot2 = RobotFactory.buildGreetRobot(robot1); + var robot3 = RobotFactory.buildManufactureRobot(); + + robot1.performTask(add); + robot1.performTask(function(a:Int, b:Int):Int { + return a - b; + }); + + robot2.performTask(function (target:Robot) { + trace('Hello, ${target.toString()}!'); + }, () -> { + trace('Cleanup...'); + }); + + robot3.performTask(function (robotType:String) { + trace('Manufacturing ${robotType}...'); + return robot2; + }); + } + + static function add(a:Int, b:Int):Int { + return a + b; + } +} \ No newline at end of file diff --git a/tests/misc/java/projects/Issue11390/Setup.hx b/tests/misc/java/projects/Issue11390/Setup.hx new file mode 100644 index 00000000000..9bcd3e92511 --- /dev/null +++ b/tests/misc/java/projects/Issue11390/Setup.hx @@ -0,0 +1,6 @@ +function main() { + Sys.setCwd("./project"); + Sys.command("javac", ["-d", "out", "test/Robot.java", "test/RobotFactory.java", "-g"]); + Sys.setCwd("./out"); + Sys.command("jar", ["cf", "test.jar", "test/Robot.class", "test/Robot$CleanupTask.class", "test/Robot$MathOperation.class", "test/Robot$GreetRobot.class", "test/Robot$ManufactureRobot.class", "test/RobotFactory.class", "test/RobotFactory$1.class", "test/RobotFactory$2.class", "test/RobotFactory$3.class"]); +} diff --git a/tests/misc/java/projects/Issue11390/compile.hxml b/tests/misc/java/projects/Issue11390/compile.hxml new file mode 100644 index 00000000000..d8c28c7e442 --- /dev/null +++ b/tests/misc/java/projects/Issue11390/compile.hxml @@ -0,0 +1,12 @@ +--main Setup +--interp + +--next + +--main Main +--java-lib project/out/test.jar +--jvm run.jar + +--next + +--cmd java -jar run.jar diff --git a/tests/misc/java/projects/Issue11390/compile.hxml.stdout b/tests/misc/java/projects/Issue11390/compile.hxml.stdout new file mode 100644 index 00000000000..195016e1fab --- /dev/null +++ b/tests/misc/java/projects/Issue11390/compile.hxml.stdout @@ -0,0 +1,10 @@ +Robot.performTask() called! +Result: 7 +Robot.performTask() called! +Result: -1 +Robot.performTask() called! +Main.hx:18: Hello, Robot! +Main.hx:20: Cleanup... +Robot.performTask() called! +Main.hx:24: Manufacturing Greet... +Output: Robot \ No newline at end of file diff --git a/tests/misc/java/projects/Issue11390/project/test/Robot.java b/tests/misc/java/projects/Issue11390/project/test/Robot.java new file mode 100644 index 00000000000..4e11f9f6fdf --- /dev/null +++ b/tests/misc/java/projects/Issue11390/project/test/Robot.java @@ -0,0 +1,42 @@ +package test; + +public abstract class Robot { + public Robot() {} + + public void performTask(T listener) { + System.out.println("Robot.performTask() called!"); + } + + public void performTask(T listener, CleanupTask cleanupTask) { + System.out.println("Robot.performTask() called!"); + cleanupTask.cleanup(); + } + + /** + * MathOperation + */ + @FunctionalInterface + public interface MathOperation { + public int operate(int a, int b); + } + + @FunctionalInterface + public interface GreetRobot { + public void greet(Robot robot); + } + + @FunctionalInterface + public interface ManufactureRobot { + public T manufacture(String robotType); + } + + @FunctionalInterface + public interface CleanupTask { + public void cleanup(); + } + + @Override + public String toString() { + return "Robot"; + } +} diff --git a/tests/misc/java/projects/Issue11390/project/test/RobotFactory.java b/tests/misc/java/projects/Issue11390/project/test/RobotFactory.java new file mode 100644 index 00000000000..d7b58d7dcb5 --- /dev/null +++ b/tests/misc/java/projects/Issue11390/project/test/RobotFactory.java @@ -0,0 +1,56 @@ +package test; + +import test.Robot.GreetRobot; +import test.Robot.ManufactureRobot; +import test.Robot.MathOperation; + +public class RobotFactory { + public static Robot buildMathRobot() { + return new Robot() { + public void performTask(MathOperation listener) { + System.out.println("Robot.performTask() called!"); + int result = listener.operate(3, 4); + System.out.println("Result: " + result); + } + + public void performTask(MathOperation listener, CleanupTask cleanupTask) { + System.out.println("Robot.performTask() called!"); + int result = listener.operate(3, 4); + System.out.println("Result: " + result); + cleanupTask.cleanup(); + } + }; + } + + public static Robot buildGreetRobot(Robot target) { + return new Robot() { + public void performTask(GreetRobot listener) { + System.out.println("Robot.performTask() called!"); + listener.greet(target); + } + + public void performTask(GreetRobot listener, CleanupTask cleanupTask) { + System.out.println("Robot.performTask() called!"); + listener.greet(target); + cleanupTask.cleanup(); + } + }; + } + + public static Robot>> buildManufactureRobot() { + return new Robot>>() { + public void performTask(ManufactureRobot> listener) { + System.out.println("Robot.performTask() called!"); + Robot output = listener.manufacture("Greet"); + System.out.println("Output: " + output.toString()); + } + + public void performTask(ManufactureRobot> listener, CleanupTask cleanupTask) { + System.out.println("Robot.performTask() called!"); + Robot output = listener.manufacture("Greet"); + System.out.println("Output: " + output.toString()); + cleanupTask.cleanup(); + } + }; + } +} From d0527173f6065bdf1b4b41b6b0c797bad964195b Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Mon, 8 Jan 2024 08:07:52 +0100 Subject: [PATCH 076/184] [tests] create out dir because some javacs don't --- tests/misc/java/projects/Issue11390/Setup.hx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/misc/java/projects/Issue11390/Setup.hx b/tests/misc/java/projects/Issue11390/Setup.hx index 9bcd3e92511..ce8c28d143d 100644 --- a/tests/misc/java/projects/Issue11390/Setup.hx +++ b/tests/misc/java/projects/Issue11390/Setup.hx @@ -1,5 +1,8 @@ +import sys.FileSystem; + function main() { Sys.setCwd("./project"); + FileSystem.createDirectory("./out"); Sys.command("javac", ["-d", "out", "test/Robot.java", "test/RobotFactory.java", "-g"]); Sys.setCwd("./out"); Sys.command("jar", ["cf", "test.jar", "test/Robot.class", "test/Robot$CleanupTask.class", "test/Robot$MathOperation.class", "test/Robot$GreetRobot.class", "test/Robot$ManufactureRobot.class", "test/RobotFactory.class", "test/RobotFactory$1.class", "test/RobotFactory$2.class", "test/RobotFactory$3.class"]); From 091b1a2e2d7555a2b818b3c03f028539a1835a75 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Mon, 8 Jan 2024 08:17:55 +0100 Subject: [PATCH 077/184] move some more things arounds to avoid nasty dependency chains --- src/codegen/codegen.ml | 12 +----------- src/codegen/overloads.ml | 10 +--------- src/context/typecore.ml | 8 ++++++++ src/core/stringHelper.ml | 11 ++++++++++- src/generators/gencs.ml | 2 +- src/generators/genjava.ml | 2 +- src/generators/genjvm.ml | 2 +- src/generators/genphp7.ml | 2 +- src/generators/genpy.ml | 2 +- src/typing/callUnification.ml | 2 +- src/typing/typeloadCheck.ml | 4 ++-- src/typing/typeloadFields.ml | 2 +- 12 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/codegen/codegen.ml b/src/codegen/codegen.ml index 393b5c88a31..9de5af5676e 100644 --- a/src/codegen/codegen.ml +++ b/src/codegen/codegen.ml @@ -65,15 +65,6 @@ let add_property_field com c = c.cl_statics <- PMap.add cf.cf_name cf c.cl_statics; c.cl_ordered_statics <- cf :: c.cl_ordered_statics -let escape_res_name name allowed = - ExtString.String.replace_chars (fun chr -> - if (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') || chr = '_' || chr = '.' then - Char.escaped chr - else if List.mem chr allowed then - Char.escaped chr - else - "-x" ^ (string_of_int (Char.code chr))) name - (* -------------------------------------------------------------------------- *) (* FIX OVERRIDES *) @@ -384,7 +375,7 @@ module Dump = struct | "pretty" -> dump_types com true | "record" -> dump_record com | "position" -> dump_position com - | _ -> dump_types com false + | _ -> dump_types com false let dump_dependencies ?(target_override=None) com = let target_name = match target_override with @@ -519,4 +510,3 @@ module ExtClass = struct let e_assign = mk (TBinop(OpAssign,ef1,e)) e.etype p in add_cl_init c e_assign end - \ No newline at end of file diff --git a/src/codegen/overloads.ml b/src/codegen/overloads.ml index 5d326efdbe9..b2096dfce58 100644 --- a/src/codegen/overloads.ml +++ b/src/codegen/overloads.ml @@ -13,7 +13,7 @@ let same_overload_args ?(get_vmtype) t1 t2 f1 f2 = | [],[] -> true | tp1 :: params1,tp2 :: params2 -> - let constraints_equal ttp1 ttp2 = + let constraints_equal ttp1 ttp2 = Ast.safe_for_all2 f_eq (get_constraints ttp2) (get_constraints ttp2) in tp1.ttp_name = tp2.ttp_name && constraints_equal tp1 tp2 && loop params1 params2 @@ -79,14 +79,6 @@ let collect_overloads map c i = loop map c; List.rev !acc -let get_overloads (com : Common.context) c i = - try - com.overload_cache#find (c.cl_path,i) - with Not_found -> - let l = collect_overloads (fun t -> t) c i in - com.overload_cache#add (c.cl_path,i) l; - l - (** Overload resolution **) module Resolution = struct diff --git a/src/context/typecore.ml b/src/context/typecore.ml index 4560788cde2..53f6071c9ba 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -758,6 +758,14 @@ let create_deprecation_context ctx = { curmod = ctx.m.curmod; } +let get_overloads (com : Common.context) c i = + try + com.overload_cache#find (c.cl_path,i) + with Not_found -> + let l = Overloads.collect_overloads (fun t -> t) c i in + com.overload_cache#add (c.cl_path,i) l; + l + (* -------------- debug functions to activate when debugging typer passes ------------------------------- *) (* diff --git a/src/core/stringHelper.ml b/src/core/stringHelper.ml index 7890d599140..ab6c57df5cd 100644 --- a/src/core/stringHelper.ml +++ b/src/core/stringHelper.ml @@ -48,4 +48,13 @@ let s_escape ?(hex=true) s = | c when int_of_char c < 32 && hex -> Buffer.add_string b (Printf.sprintf "\\x%.2X" (int_of_char c)) | c -> Buffer.add_char b c done; - Buffer.contents b \ No newline at end of file + Buffer.contents b + +let escape_res_name name allowed = + ExtString.String.replace_chars (fun chr -> + if (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') || chr = '_' || chr = '.' then + Char.escaped chr + else if List.mem chr allowed then + Char.escaped chr + else + "-x" ^ (string_of_int (Char.code chr))) name \ No newline at end of file diff --git a/src/generators/gencs.ml b/src/generators/gencs.ml index 08002d807ef..77891fc7fe1 100644 --- a/src/generators/gencs.ml +++ b/src/generators/gencs.ml @@ -3420,7 +3420,7 @@ let generate con = gen.gcon.file ^ "/src/Resources" in Hashtbl.iter (fun name v -> - let name = Codegen.escape_res_name name ['/'] in + let name = StringHelper.escape_res_name name ['/'] in let full_path = src ^ "/" ^ name in Path.mkdir_from_path full_path; diff --git a/src/generators/genjava.ml b/src/generators/genjava.ml index 71e199d6cb8..806777b26e1 100644 --- a/src/generators/genjava.ml +++ b/src/generators/genjava.ml @@ -2652,7 +2652,7 @@ let generate con = let res = ref [] in Hashtbl.iter (fun name v -> res := { eexpr = TConst(TString name); etype = gen.gcon.basic.tstring; epos = null_pos } :: !res; - let name = Codegen.escape_res_name name ['/'] in + let name = StringHelper.escape_res_name name ['/'] in let full_path = gen.gcon.file ^ "/src/" ^ name in Path.mkdir_from_path full_path; diff --git a/src/generators/genjvm.ml b/src/generators/genjvm.ml index 6e6c7e358e6..657c594be02 100644 --- a/src/generators/genjvm.ml +++ b/src/generators/genjvm.ml @@ -3102,7 +3102,7 @@ let generate jvm_flag com = end ) com.native_libs.java_libs in Hashtbl.iter (fun name v -> - let filename = Codegen.escape_res_name name ['/';'-'] in + let filename = StringHelper.escape_res_name name ['/';'-'] in gctx.out#add_entry v filename; ) com.resources; let generate_real_types () = diff --git a/src/generators/genphp7.ml b/src/generators/genphp7.ml index 288a9168cd3..bd8fc426304 100644 --- a/src/generators/genphp7.ml +++ b/src/generators/genphp7.ml @@ -35,7 +35,7 @@ let write_resource dir name data = let rdir = dir ^ "/res" in if not (Sys.file_exists dir) then Unix.mkdir dir 0o755; if not (Sys.file_exists rdir) then Unix.mkdir rdir 0o755; - let name = Codegen.escape_res_name name [] in + let name = StringHelper.escape_res_name name [] in let ch = open_out_bin (rdir ^ "/" ^ name) in output_string ch data; close_out ch diff --git a/src/generators/genpy.ml b/src/generators/genpy.ml index 3e42aa58628..72abdd12e65 100644 --- a/src/generators/genpy.ml +++ b/src/generators/genpy.ml @@ -2269,7 +2269,7 @@ module Generator = struct end else "," in - let k_enc = Codegen.escape_res_name k [] in + let k_enc = StringHelper.escape_res_name k [] in print ctx "%s\"%s\": open('%%s.%%s'%%(_file,'%s'),'rb').read()" prefix (StringHelper.s_escape k) k_enc; let f = open_out_bin (ctx.com.file ^ "." ^ k_enc) in diff --git a/src/typing/callUnification.ml b/src/typing/callUnification.ml index 913beb90c2f..9beeb73bc08 100644 --- a/src/typing/callUnification.ml +++ b/src/typing/callUnification.ml @@ -228,7 +228,7 @@ let unify_field_call ctx fa el_typed el p inline = else List.map (fun (t,cf) -> cf - ) (Overloads.get_overloads ctx.com c cf.cf_name) + ) (get_overloads ctx.com c cf.cf_name) in cfl,Some c,false,TClass.get_map_function c tl,(fun t -> t) | FHAbstract(a,tl,c) -> diff --git a/src/typing/typeloadCheck.ml b/src/typing/typeloadCheck.ml index 14f3169c440..faaabe9ff12 100644 --- a/src/typing/typeloadCheck.ml +++ b/src/typing/typeloadCheck.ml @@ -243,7 +243,7 @@ let check_overriding ctx c f = let p = f.cf_name_pos in let i = f.cf_name in if has_class_field_flag f CfOverload then begin - let overloads = Overloads.get_overloads ctx.com csup i in + let overloads = get_overloads ctx.com csup i in List.iter (fun (t,f2) -> (* check if any super class fields are vars *) match f2.cf_kind with @@ -378,7 +378,7 @@ module Inheritance = struct let map2, t2, f2 = class_field_no_interf c f.cf_name in let t2, f2 = if f2.cf_overloads <> [] || has_class_field_flag f2 CfOverload then - let overloads = Overloads.get_overloads ctx.com c f.cf_name in + let overloads = get_overloads ctx.com c f.cf_name in is_overload := true; List.find (fun (t1,f1) -> Overloads.same_overload_args t t1 f f1) overloads else diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index 9651bd3618b..7d54adb071e 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -1475,7 +1475,7 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p = let cf = PMap.find m c.cl_statics in (cf.cf_type,cf) :: (List.map (fun cf -> cf.cf_type,cf) cf.cf_overloads) end else - Overloads.get_overloads ctx.com c m + get_overloads ctx.com c m in let cf = { (mk_field name ~public:(is_public (ctx,cctx) f.cff_access None) ret f.cff_pos (pos f.cff_name)) with From e6746636dfce03f793cfb00ad22091c1d31fe8f3 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Mon, 8 Jan 2024 08:39:36 +0100 Subject: [PATCH 078/184] move abort to Error no reason to depend on common.ml just for that --- src/codegen/gencommon/gencommon.ml | 2 +- src/context/common.ml | 4 +--- src/context/display/displayPath.ml | 4 ++-- src/core/error.ml | 2 ++ src/filters/ES6Ctors.ml | 2 +- src/generators/gencpp.ml | 1 + src/generators/gencs.ml | 6 +++--- src/generators/genhl.ml | 1 + src/generators/genjs.ml | 1 + src/generators/genneko.ml | 6 +++--- src/generators/genpy.ml | 1 + src/generators/genswf.ml | 1 + src/generators/genswf9.ml | 1 + src/generators/hlinterp.ml | 2 +- src/optimization/analyzerTypes.ml | 2 +- 15 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/codegen/gencommon/gencommon.ml b/src/codegen/gencommon/gencommon.ml index 5324ae9c0f6..c800e688c4b 100644 --- a/src/codegen/gencommon/gencommon.ml +++ b/src/codegen/gencommon/gencommon.ml @@ -819,7 +819,7 @@ let run_filters gen = reorder_modules gen; t(); - if !has_errors then abort "Compilation aborted with errors" null_pos + if !has_errors then Error.abort "Compilation aborted with errors" null_pos (* ******************************************* *) (* basic generation module that source code compilation implementations can use *) diff --git a/src/context/common.ml b/src/context/common.ml index 8f6f5bb4ac3..b972218db0a 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -1053,8 +1053,6 @@ let allow_package ctx s = with Not_found -> () -let abort ?(depth = 0) msg p = raise (Error.Fatal_error (Error.make_error ~depth (Custom msg) p)) - let platform ctx p = ctx.platform = p let platform_name_macro com = @@ -1208,7 +1206,7 @@ let to_utf8 str p = let ccount = ref 0 in UTF8.iter (fun c -> let c = UCharExt.code c in - if (c >= 0xD800 && c <= 0xDFFF) || c >= 0x110000 then abort "Invalid unicode char" p; + if (c >= 0xD800 && c <= 0xDFFF) || c >= 0x110000 then Error.abort "Invalid unicode char" p; incr ccount; if c > 0x10000 then incr ccount; ) u8; diff --git a/src/context/display/displayPath.ml b/src/context/display/displayPath.ml index 6ad580d420a..83f719fcea9 100644 --- a/src/context/display/displayPath.ml +++ b/src/context/display/displayPath.ml @@ -83,7 +83,7 @@ module TypePathHandler = struct let complete_type_path com p = let packs, modules = read_type_path com p in if packs = [] && modules = [] then - (abort ("No modules found in " ^ String.concat "." p) null_pos) + (Error.abort ("No modules found in " ^ String.concat "." p) null_pos) else let packs = List.map (fun n -> make_ci_package (p,n) []) packs in let modules = List.map (fun n -> make_ci_module (p,n)) modules in @@ -158,7 +158,7 @@ module TypePathHandler = struct in Some fields with _ -> - abort ("Could not load module " ^ (s_type_path (p,c))) null_pos + Error.abort ("Could not load module " ^ (s_type_path (p,c))) null_pos end let resolve_position_by_path ctx path p = diff --git a/src/core/error.ml b/src/core/error.ml index 872d9579e1d..c1b2232693c 100644 --- a/src/core/error.ml +++ b/src/core/error.ml @@ -51,6 +51,8 @@ let rec recurse_error ?(depth = 0) cb err = exception Fatal_error of error exception Error of error +let abort ?(depth = 0) msg p = raise (Fatal_error (make_error ~depth (Custom msg) p)) + let string_source t = match follow t with | TInst(c,tl) -> PMap.foldi (fun s _ acc -> s :: acc) (TClass.get_all_fields c tl) [] | TAnon a -> PMap.fold (fun cf acc -> cf.cf_name :: acc) a.a_fields [] diff --git a/src/filters/ES6Ctors.ml b/src/filters/ES6Ctors.ml index 9ba083d70fc..8dd2b526fcb 100644 --- a/src/filters/ES6Ctors.ml +++ b/src/filters/ES6Ctors.ml @@ -84,7 +84,7 @@ let rewrite_ctors com = let rec mark_needs_ctor_skipping cl = (* for non haxe-generated extern classes we can't generate any valid code, so just fail *) if (has_class_flag cl CExtern) && not (Meta.has Meta.HxGen cl.cl_meta) then begin - abort "Must call `super()` constructor before accessing `this` in classes derived from an extern class with constructor" p_this_access; + Error.abort "Must call `super()` constructor before accessing `this` in classes derived from an extern class with constructor" p_this_access; end; try Hashtbl.find needs_ctor_skipping cl.cl_path diff --git a/src/generators/gencpp.ml b/src/generators/gencpp.ml index 264bb28276b..4d034be9ad0 100644 --- a/src/generators/gencpp.ml +++ b/src/generators/gencpp.ml @@ -19,6 +19,7 @@ open Extlib_leftovers open Ast open Type +open Error open Common open Globals diff --git a/src/generators/gencs.ml b/src/generators/gencs.ml index 77891fc7fe1..e20b13400ba 100644 --- a/src/generators/gencs.ml +++ b/src/generators/gencs.ml @@ -1798,7 +1798,7 @@ let generate con = let code, code_pos = match code.eexpr with | TConst (TString s) -> s, code.epos - | _ -> abort "The `code` argument for cs.Syntax.code must be a string constant" code.epos + | _ -> Error.abort "The `code` argument for cs.Syntax.code must be a string constant" code.epos in begin let rec reveal_expr expr = @@ -1820,11 +1820,11 @@ let generate con = let code = match code.eexpr with | TConst (TString s) -> s - | _ -> abort "The `code` argument for cs.Syntax.plainCode must be a string constant" code.epos + | _ -> Error.abort "The `code` argument for cs.Syntax.plainCode must be a string constant" code.epos in write w (String.concat "\n" (ExtString.String.nsplit code "\r\n")) | _ -> - abort (Printf.sprintf "Unknown cs.Syntax method `%s` with %d arguments" meth (List.length args)) pos + Error.abort (Printf.sprintf "Unknown cs.Syntax method `%s` with %d arguments" meth (List.length args)) pos and do_call w e el = let params, el = extract_tparams [] el in let params = List.rev params in diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index b57f56c127d..b00adbdf181 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -23,6 +23,7 @@ open Extlib_leftovers open Globals open Ast open Type +open Error open Common open Hlcode diff --git a/src/generators/genjs.ml b/src/generators/genjs.ml index ba525b198e4..53fe22012f3 100644 --- a/src/generators/genjs.ml +++ b/src/generators/genjs.ml @@ -20,6 +20,7 @@ open Extlib_leftovers open Globals open Ast open Type +open Error open Common open JsSourcemap diff --git a/src/generators/genneko.ml b/src/generators/genneko.ml index 85cf32bf27c..3830fc0ac3e 100644 --- a/src/generators/genneko.ml +++ b/src/generators/genneko.ml @@ -170,7 +170,7 @@ let gen_constant ctx pe c = if (h land 128 = 0) <> (h land 64 = 0) then raise Exit; int p (Int32.to_int i) with _ -> - if ctx.version < 2 then abort "This integer is too big to be compiled to a Neko 31-bit integer. Please use a Float instead" pe; + if ctx.version < 2 then Error.abort "This integer is too big to be compiled to a Neko 31-bit integer. Please use a Float instead" pe; (EConst (Int32 i),p)) | TFloat f -> (EConst (Float (Texpr.replace_separators f "")),p) | TString s -> call p (field p (ident p "String") "new") [gen_big_string ctx p s] @@ -237,7 +237,7 @@ and gen_expr ctx e = (match follow e.etype with | TFun (args,_) -> let n = List.length args in - if n > 5 then abort "Cannot create closure with more than 5 arguments" e.epos; + if n > 5 then Error.abort "Cannot create closure with more than 5 arguments" e.epos; let tmp = ident p "@tmp" in EBlock [ (EVars ["@tmp", Some (gen_expr ctx e2); "@fun", Some (field p tmp f.cf_name)] , p); @@ -798,7 +798,7 @@ let generate com = else loop (p + 1) in - abort msg (loop 0) + Error.abort msg (loop 0) end; let command cmd args = try com.run_command_args cmd args with _ -> -1 in let neko_file = (try Filename.chop_extension com.file with _ -> com.file) ^ ".neko" in diff --git a/src/generators/genpy.ml b/src/generators/genpy.ml index 72abdd12e65..d836c37695c 100644 --- a/src/generators/genpy.ml +++ b/src/generators/genpy.ml @@ -19,6 +19,7 @@ open Extlib_leftovers open Globals open Ast +open Error open Type open Common open Texpr.Builder diff --git a/src/generators/genswf.ml b/src/generators/genswf.ml index c37632448a6..c6b4f60765a 100644 --- a/src/generators/genswf.ml +++ b/src/generators/genswf.ml @@ -20,6 +20,7 @@ open Swf open As3hl open ExtString open Type +open Error open Common open Ast open Globals diff --git a/src/generators/genswf9.ml b/src/generators/genswf9.ml index d34ba33fc47..4ea67eddb7c 100644 --- a/src/generators/genswf9.ml +++ b/src/generators/genswf9.ml @@ -20,6 +20,7 @@ open Extlib_leftovers open Globals open Ast open Type +open Error open As3 open As3hl open Common diff --git a/src/generators/hlinterp.ml b/src/generators/hlinterp.ml index c60b06cf30c..8c32aced375 100644 --- a/src/generators/hlinterp.ml +++ b/src/generators/hlinterp.ml @@ -2209,7 +2209,7 @@ let check code macros = Globals.pmin = low; Globals.pmax = low + (dline lsr 20); } in - Common.abort msg pos + Error.abort msg pos end else failwith (Printf.sprintf "\n%s:%d: %s" file dline msg) in diff --git a/src/optimization/analyzerTypes.ml b/src/optimization/analyzerTypes.ml index 99ffb0cddcc..5a1fd0d6925 100644 --- a/src/optimization/analyzerTypes.ml +++ b/src/optimization/analyzerTypes.ml @@ -218,7 +218,7 @@ module BasicBlock = struct bb let in_scope bb bb' = match bb'.bb_scopes with - | [] -> abort (Printf.sprintf "Scope-less block (kind: %s)" (s_block_kind bb'.bb_kind)) bb'.bb_pos + | [] -> Error.abort (Printf.sprintf "Scope-less block (kind: %s)" (s_block_kind bb'.bb_kind)) bb'.bb_pos | scope :: _ -> List.mem scope bb.bb_scopes let terminator_map f term = match term with From 05631cdb2d4b513543f535b5881bd4a1effa22cc Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Mon, 8 Jan 2024 10:22:43 +0100 Subject: [PATCH 079/184] [typer] move std to common, avoid more explicit ([],"Std") --- src/codegen/codegen.ml | 11 +---------- src/context/common.ml | 3 +++ src/context/typecore.ml | 1 - src/core/texpr.ml | 15 +++++++++++++++ src/filters/exceptions.ml | 2 +- src/typing/operators.ml | 6 +----- src/typing/typer.ml | 11 +---------- src/typing/typerBase.ml | 3 --- src/typing/typerEntry.ml | 3 +-- 9 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/codegen/codegen.ml b/src/codegen/codegen.ml index 9de5af5676e..42fe3a04136 100644 --- a/src/codegen/codegen.ml +++ b/src/codegen/codegen.ml @@ -419,16 +419,7 @@ let default_cast ?(vtmp="$t") com e texpr t p = let var = mk (TVar (vtmp,Some e)) api.tvoid p in let vexpr = mk (TLocal vtmp) e.etype p in let texpr = Texpr.Builder.make_typeexpr texpr p in - let std = (try List.find (fun t -> t_path t = ([],"Std")) com.types with Not_found -> die "" __LOC__) in - let fis = (try - let c = (match std with TClassDecl c -> c | _ -> die "" __LOC__) in - FStatic (c, PMap.find "isOfType" c.cl_statics) - with Not_found -> - die "" __LOC__ - ) in - let std = Texpr.Builder.make_typeexpr std p in - let is = mk (TField (std,fis)) (tfun [t_dynamic;t_dynamic] api.tbool) p in - let is = mk (TCall (is,[vexpr;texpr])) api.tbool p in + let is = Texpr.Builder.resolve_and_make_static_call com.std "isOfType" [vexpr;texpr] p in let enull = Texpr.Builder.make_null vexpr.etype p in let eop = Texpr.Builder.binop OpEq vexpr enull api.tbool p in let echeck = Texpr.Builder.binop OpBoolOr is eop api.tbool p in diff --git a/src/context/common.ml b/src/context/common.ml index b972218db0a..4f7890f2da9 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -375,6 +375,7 @@ type context = { mutable user_metas : (string, Meta.user_meta) Hashtbl.t; mutable get_macros : unit -> context option; (* typing state *) + mutable std : tclass; mutable global_metadata : (string list * metadata_entry * (bool * bool * bool)) list; shared : shared_context; display_information : display_information; @@ -855,6 +856,7 @@ let create compilation_step cs version args display_mode = tnull = (fun _ -> die "Could use locate abstract Null (was it redefined?)" __LOC__); tarray = (fun _ -> die "Could not locate class Array (was it redefined?)" __LOC__); }; + std = null_class; file_lookup_cache = new hashtbl_lookup; file_keys = new file_keys; file_contents = []; @@ -914,6 +916,7 @@ let clone com is_macro_context = module_to_file = new hashtbl_lookup; overload_cache = new hashtbl_lookup; module_lut = new module_lut; + std = null_class; } let file_time file = Extc.filetime file diff --git a/src/context/typecore.ml b/src/context/typecore.ml index 53f6071c9ba..1d5ac7e250d 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -100,7 +100,6 @@ type typer_globals = { retain_meta : bool; mutable core_api : typer option; mutable macros : ((unit -> unit) * typer) option; - mutable std : tclass; mutable std_types : module_def; type_patches : (path, (string * bool, type_patch) Hashtbl.t * type_patch) Hashtbl.t; mutable module_check_policies : (string list * module_check_policy list * bool) list; diff --git a/src/core/texpr.ml b/src/core/texpr.ml index 3082e210b04..8cb6b3061bb 100644 --- a/src/core/texpr.ml +++ b/src/core/texpr.ml @@ -561,6 +561,21 @@ module Builder = struct let index basic e index t p = mk (TArray (e,mk (TConst (TInt (Int32.of_int index))) basic.tint p)) t p + + let resolve_and_make_static_call c name args p = + ignore(c.cl_build()); + let cf = try + PMap.find name c.cl_statics + with Not_found -> + die "" __LOC__ + in + let ef = make_static_field c cf (mk_zero_range_pos p) in + let tret = match follow ef.etype with + | TFun(_,r) -> r + | _ -> assert false + in + mk (TCall (ef, args)) tret p + end let set_default basic a c p = diff --git a/src/filters/exceptions.ml b/src/filters/exceptions.ml index 98003ee7e9f..08347da7ebc 100644 --- a/src/filters/exceptions.ml +++ b/src/filters/exceptions.ml @@ -63,7 +63,7 @@ let haxe_exception_instance_call ctx haxe_exception method_name args p = *) let std_is ctx e t p = let t = follow t in - let std_cls = ctx.typer.g.std in + let std_cls = ctx.typer.com.std in let isOfType_field = try PMap.find "isOfType" std_cls.cl_statics with Not_found -> raise_typing_error ("Std has no field isOfType") p diff --git a/src/typing/operators.ml b/src/typing/operators.ml index b9f0b7c927b..ba188a434f2 100644 --- a/src/typing/operators.ml +++ b/src/typing/operators.ml @@ -201,11 +201,7 @@ let make_binop ctx op e1 e2 is_assign_op p = call_to_string ctx e | KInt | KFloat | KString -> e | KUnk | KDyn | KNumParam _ | KStrParam _ | KOther -> - let std = type_type ctx ([],"Std") e.epos in - let acc = acc_get ctx (type_field_default_cfg ctx std "string" e.epos (MCall []) WithType.value) in - ignore(follow acc.etype); - let acc = (match acc.eexpr with TField (e,FClosure (Some (c,tl),f)) -> { acc with eexpr = TField (e,FInstance (c,tl,f)) } | _ -> acc) in - make_call ctx acc [e] ctx.t.tstring e.epos + Texpr.Builder.resolve_and_make_static_call ctx.com.std "string" [e] e.epos | KAbstract (a,tl) -> try AbstractCast.cast_or_unify_raise ctx tstring e p diff --git a/src/typing/typer.ml b/src/typing/typer.ml index ef95b897573..6fad5ed24a5 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -2014,16 +2014,7 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) = if ctx.in_display && DisplayPosition.display_position#enclosed_in p_t then DisplayEmitter.display_module_type ctx mt p_t; let e_t = type_module_type ctx mt p_t in - let e_Std_isOfType = - ignore(ctx.g.std.cl_build()); - let cf = try - PMap.find "isOfType" ctx.g.std.cl_statics - with Not_found -> - die "" __LOC__ - in - Texpr.Builder.make_static_field ctx.g.std cf (mk_zero_range_pos p) - in - mk (TCall (e_Std_isOfType, [e; e_t])) ctx.com.basic.tbool p + Texpr.Builder.resolve_and_make_static_call ctx.com.std "isOfType" [e;e_t] p | _ -> display_error ctx.com "Unsupported type for `is` operator" p_t; Texpr.Builder.make_bool ctx.com.basic false p diff --git a/src/typing/typerBase.ml b/src/typing/typerBase.ml index ddfbb114991..48542971600 100644 --- a/src/typing/typerBase.ml +++ b/src/typing/typerBase.ml @@ -232,9 +232,6 @@ let type_module_type ctx t p = in loop t None -let type_type ctx tpath p = - type_module_type ctx (Typeload.load_type_def ctx p (mk_type_path tpath)) p - let mk_module_type_access ctx t p = AKExpr (type_module_type ctx t p) diff --git a/src/typing/typerEntry.ml b/src/typing/typerEntry.ml index 94f2c315287..0a57a36f729 100644 --- a/src/typing/typerEntry.ml +++ b/src/typing/typerEntry.ml @@ -20,7 +20,6 @@ let create com macros = doinline = com.display.dms_inline && not (Common.defined com Define.NoInline); retain_meta = Common.defined com Define.RetainUntypedMeta; std_types = null_module; - std = null_class; global_using = []; complete = false; type_hints = []; @@ -135,7 +134,7 @@ let create com macros = ) m.m_types; let m = TypeloadModule.load_module ctx ([],"Std") null_pos in List.iter (fun mt -> match mt with - | TClassDecl ({cl_path = ([],"Std")} as c) -> ctx.g.std <- c; + | TClassDecl ({cl_path = ([],"Std")} as c) -> ctx.com.std <- c; | _ -> () ) m.m_types; let m = TypeloadModule.load_module ctx ([],"Array") null_pos in From 26807acb412eb952f3a7923a8f3d68acb4ed9ee2 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Mon, 8 Jan 2024 19:10:52 +0100 Subject: [PATCH 080/184] [server] guard against the null module being added as a dependency closes #11463 --- src/compiler/server.ml | 6 +++++- src/core/tFunctions.ml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/compiler/server.ml b/src/compiler/server.ml index ac6fc9aca88..e9c061af69c 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -312,7 +312,11 @@ let check_module sctx ctx m p = in let check_dependencies () = PMap.iter (fun _ (sign,mpath) -> - let m2 = (com.cs#get_context sign)#find_module mpath in + let m2 = try + (com.cs#get_context sign)#find_module mpath + with Not_found -> + die (Printf.sprintf "Could not find dependency %s of %s in the cache" (s_type_path mpath) (s_type_path m.m_path)) __LOC__; + in match check m2 with | None -> () | Some reason -> raise (Dirty (DependencyDirty(m2.m_path,reason))) diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index 247970f5428..862a994004e 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -283,7 +283,7 @@ let null_abstract = { } let add_dependency ?(skip_postprocess=false) m mdep = - if m != null_module && (m.m_path != mdep.m_path || m.m_extra.m_sign != mdep.m_extra.m_sign) then begin + if m != null_module && mdep != null_module && (m.m_path != mdep.m_path || m.m_extra.m_sign != mdep.m_extra.m_sign) then begin m.m_extra.m_deps <- PMap.add mdep.m_id (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 From 822dd87c1e7e56caac29aa3d42eb7879edeebade Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Tue, 9 Jan 2024 14:11:37 +0100 Subject: [PATCH 081/184] [typer] remove Directory package rule because it is unused --- src/context/common.ml | 1 - src/context/display/displayPath.ml | 2 -- src/context/display/displayToplevel.ml | 1 - src/macro/macroApi.ml | 1 - src/typing/typeloadParse.ml | 9 ++------- 5 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/context/common.ml b/src/context/common.ml index 4f7890f2da9..89d0444e83d 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -27,7 +27,6 @@ open Warning type package_rule = | Forbidden - | Directory of string | Remap of string type pos = Globals.pos diff --git a/src/context/display/displayPath.ml b/src/context/display/displayPath.ml index 83f719fcea9..6b233825fe5 100644 --- a/src/context/display/displayPath.ml +++ b/src/context/display/displayPath.ml @@ -26,7 +26,6 @@ module TypePathHandler = struct | x :: l -> (try match PMap.find x com.package_rules with - | Directory d -> d :: l | Remap s -> s :: l | _ -> p with @@ -47,7 +46,6 @@ module TypePathHandler = struct match PMap.find f com.package_rules with | Forbidden -> () | Remap f -> packages := f :: !packages - | Directory _ -> raise Not_found with Not_found -> packages := f :: !packages else diff --git a/src/context/display/displayToplevel.ml b/src/context/display/displayToplevel.ml index a7c07716429..f5959f19e3e 100644 --- a/src/context/display/displayToplevel.ml +++ b/src/context/display/displayToplevel.ml @@ -74,7 +74,6 @@ class explore_class_path_task com checked recursive f_pack f_module dir pack = o begin try begin match PMap.find file com.package_rules with | Forbidden | Remap _ -> () - | _ -> raise Not_found end with Not_found -> f_pack (List.rev pack,file); diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index deb6553c1dd..722b1d5c2c9 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -516,7 +516,6 @@ and encode_exceptions_config ec = and encode_package_rule pr = let tag, pl = match pr with | Forbidden -> 0, [] - | Directory (path) -> 1, [encode_string path] | Remap (path) -> 2, [encode_string path] in encode_enum ~pos:None IPackageRule tag pl diff --git a/src/typing/typeloadParse.ml b/src/typing/typeloadParse.ml index 481c451236d..29f99f48f5a 100644 --- a/src/typing/typeloadParse.ml +++ b/src/typing/typeloadParse.ml @@ -82,25 +82,20 @@ let parse_hook = ref parse_file let resolve_module_file com m remap p = let forbid = ref false in - let compose_path no_rename = + let compose_path = (match m with | [] , name -> name | x :: l , name -> let x = (try match PMap.find x com.package_rules with | Forbidden -> forbid := true; x - | Directory d -> if no_rename then x else d | Remap d -> remap := d :: l; d with Not_found -> x ) in String.concat "/" (x :: l) ^ "/" ^ name ) ^ ".hx" in - let file = try - Common.find_file com (compose_path false) - with Not_found -> - Common.find_file com (compose_path true) - in + let file = Common.find_file com compose_path in 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 *) From 19517c00adda9dffe64c94265649aaca7ec256f4 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Tue, 9 Jan 2024 16:50:57 +0100 Subject: [PATCH 082/184] [typer] remove Forbid_package try/with This is from a time (issue #1152) when module resolution was reflected on the call stack. With the typer pass system it's unlikely to ever catch anything we want to catch. --- src/typing/typeloadModule.ml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/typing/typeloadModule.ml b/src/typing/typeloadModule.ml index 014eec7787c..aebf0f032e6 100644 --- a/src/typing/typeloadModule.ml +++ b/src/typing/typeloadModule.ml @@ -809,10 +809,7 @@ let load_module' ctx g m p = loop ctx.com.load_extern_type in let is_extern = !is_extern in - try - type_module ctx m file ~is_extern decls p - with Forbid_package (inf,pl,pf) when p <> null_pos -> - raise (Forbid_package (inf,p::pl,pf)) + type_module ctx m file ~is_extern decls p let load_module ctx m p = let m2 = load_module' ctx ctx.g m p in From 944d4fdba9cce40d0e00c3a2495d0180e6e1f3c5 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 10 Jan 2024 10:33:46 +0100 Subject: [PATCH 083/184] [macro] don't apply @:native names closes #11481 --- src/typing/macroContext.ml | 1 - tests/misc/projects/Issue11481/Main.hx | 3 +++ tests/misc/projects/Issue11481/compile.hxml | 2 ++ tests/misc/projects/Issue11481/compile.hxml.stdout | 1 + tests/misc/projects/Issue11481/pack/OldClass.hx | 12 ++++++++++++ 5 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/misc/projects/Issue11481/Main.hx create mode 100644 tests/misc/projects/Issue11481/compile.hxml create mode 100644 tests/misc/projects/Issue11481/compile.hxml.stdout create mode 100644 tests/misc/projects/Issue11481/pack/OldClass.hx diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index d5df49e80bb..d349eb5be50 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -664,7 +664,6 @@ and flush_macro_context mint mctx = Exceptions.patch_constructors mctx; (fun mt -> AddFieldInits.add_field_inits mctx.curclass.cl_path (RenameVars.init mctx.com) mctx.com mt); minimal_restore; - Naming.apply_native_paths ] in let ready = fun t -> FiltersCommon.apply_filters_once mctx expr_filters t; diff --git a/tests/misc/projects/Issue11481/Main.hx b/tests/misc/projects/Issue11481/Main.hx new file mode 100644 index 00000000000..4d95c5f0be2 --- /dev/null +++ b/tests/misc/projects/Issue11481/Main.hx @@ -0,0 +1,3 @@ +function main() { + trace(pack.OldClass); +} \ No newline at end of file diff --git a/tests/misc/projects/Issue11481/compile.hxml b/tests/misc/projects/Issue11481/compile.hxml new file mode 100644 index 00000000000..5f82c470c12 --- /dev/null +++ b/tests/misc/projects/Issue11481/compile.hxml @@ -0,0 +1,2 @@ +-m Main +--interp \ No newline at end of file diff --git a/tests/misc/projects/Issue11481/compile.hxml.stdout b/tests/misc/projects/Issue11481/compile.hxml.stdout new file mode 100644 index 00000000000..a4310c6c4f8 --- /dev/null +++ b/tests/misc/projects/Issue11481/compile.hxml.stdout @@ -0,0 +1 @@ +Main.hx:2: Class \ No newline at end of file diff --git a/tests/misc/projects/Issue11481/pack/OldClass.hx b/tests/misc/projects/Issue11481/pack/OldClass.hx new file mode 100644 index 00000000000..163b567c747 --- /dev/null +++ b/tests/misc/projects/Issue11481/pack/OldClass.hx @@ -0,0 +1,12 @@ +package pack; + +@:native("NewClass") +class OldClass { + macro static function f2() { + return null; + } + + macro static function f1() { + return null; + } +} \ No newline at end of file From 682b8e3407cf04bb0b81275d6543cc9c45e00e89 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Wed, 10 Jan 2024 13:49:27 +0100 Subject: [PATCH 084/184] [server] remove retyper This didn't quite work the way I wanted it to, and it will become obsolete with a hxb-based cache anyway. --- src/compiler/retyper.ml | 277 ------------------------- src/compiler/server.ml | 14 -- src/core/tType.ml | 1 - std/haxe/macro/CompilationServer.hx | 4 - tests/server/src/cases/RetyperTests.hx | 203 ------------------ 5 files changed, 499 deletions(-) delete mode 100644 src/compiler/retyper.ml delete mode 100644 tests/server/src/cases/RetyperTests.hx diff --git a/src/compiler/retyper.ml b/src/compiler/retyper.ml deleted file mode 100644 index e5f313e98b6..00000000000 --- a/src/compiler/retyper.ml +++ /dev/null @@ -1,277 +0,0 @@ -open Globals -open Ast -open Typecore -open Type -open TypeloadModule -open TypeloadFields - -exception Fail of string - -type retyping_context = { - typer : typer; - print_stack : string list; -} - -let fail rctx s = - let stack = String.concat " " (List.rev rctx.print_stack) in - raise (Fail (Printf.sprintf "%s: %s" stack s)) - -let disable_typeloading rctx ctx f = - let old = ctx.g.load_only_cached_modules in - ctx.g.load_only_cached_modules <- true; - try - Std.finally (fun () -> ctx.g.load_only_cached_modules <- old) f () - with (Error.Error { err_message = Module_not_found path }) -> - fail rctx (Printf.sprintf "Could not load [Module %s]" (s_type_path path)) - -let pair_type th t = match th with - | None -> - TExprToExpr.convert_type t,null_pos - | Some t -> - t - -let pair_class_field rctx ctx cctx fctx cf cff p = - match cff.cff_kind with - | FFun fd -> - let targs,tret = match follow cf.cf_type with - | TFun(args,ret) -> - args,ret - | _ -> - fail rctx "Type change" - in - let args = try - List.map2 (fun (name,opt,meta,th,eo) (_,_,t) -> - (name,opt,meta,Some (pair_type th t),eo) - ) fd.f_args targs - with Invalid_argument _ -> - fail rctx "Type change" - in - let ret = pair_type fd.f_type tret in - let fd = { - fd with - f_args = args; - f_type = Some ret - } in - let load_args_ret () = - setup_args_ret ctx cctx fctx (fst cff.cff_name) fd p - in - let args,ret = disable_typeloading rctx ctx load_args_ret in - let t = TFun(args#for_type,ret) in - (fun () -> - (* This is the only part that should actually modify anything. *) - cf.cf_type <- t; - TypeBinding.bind_method ctx cctx fctx cf t args ret fd.f_expr (match fd.f_expr with Some e -> snd e | None -> cff.cff_pos); - if ctx.com.display.dms_full_typing then - remove_class_field_flag cf CfPostProcessed; - ) - | FVar(th,eo) | FProp(_,_,th,eo) -> - let th = Some (pair_type th cf.cf_type) in - let t = disable_typeloading rctx ctx (fun () -> load_variable_type_hint ctx fctx eo (pos cff.cff_name) th) in - (fun () -> - cf.cf_type <- t; - TypeBinding.bind_var ctx cctx fctx cf eo; - if ctx.com.display.dms_full_typing then - remove_class_field_flag cf CfPostProcessed; - ) - -let pair_classes rctx c d p = - let rctx = {rctx with - print_stack = (Printf.sprintf "[Class %s]" (s_type_path c.cl_path)) :: rctx.print_stack - } in - c.cl_restore(); - (* TODO: What do we do with build macros? *) - let cctx = create_class_context c p in - let ctx = create_typer_context_for_class rctx.typer cctx p in - let _ = - let rctx = {rctx with - print_stack = (Printf.sprintf "[Relations]") :: rctx.print_stack - } in - let has_extends = ref false in - let implements = ref c.cl_implements in - List.iter (function - | HExtends ptp -> - has_extends := true; - begin match c.cl_super with - | None -> - fail rctx (Printf.sprintf "parent %s appeared" (Ast.Printer.s_complex_type_path "" ptp)) - | Some(c,tl) -> - let th = pair_type (Some(CTPath ptp,ptp.pos_full)) (TInst(c,tl)) in - ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false th)) - end - | HImplements ptp -> - begin match !implements with - | (c,tl) :: rest -> - (* TODO: I think this should somehow check if it's actually the same interface. There could be cases - where the order changes or something like that... Maybe we can compare the loaded type. - However, this doesn't matter until we start retyping invalidated modules. - *) - implements := rest; - let th = pair_type (Some(CTPath ptp,ptp.pos_full)) (TInst(c,tl)) in - ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false th)); - | [] -> - fail rctx (Printf.sprintf "interface %s appeared" (Ast.Printer.s_complex_type_path "" ptp)) - end - | _ -> - () - ) d.d_flags; - (* TODO: There are probably cases where the compiler generates a cl_super even though it's not in syntax *) - if not !has_extends then begin match c.cl_super with - | None -> () - | Some(c,_) -> fail rctx (Printf.sprintf "parent %s disappeared" (s_type_path c.cl_path)) - end; - begin match !implements with - | (c,_) :: _ -> fail rctx (Printf.sprintf "interface %s disappeared" (s_type_path c.cl_path)) - | [] -> () - end - in - let fl = List.map (fun cff -> - let name = fst cff.cff_name in - let rctx = {rctx with - print_stack = (Printf.sprintf "[Field %s]" name) :: rctx.print_stack - } in - let display_modifier = Typeload.check_field_access ctx cff in - let fctx = create_field_context ctx cctx cff ctx.is_display_file display_modifier in - let cf = match fctx.field_kind with - | FKConstructor -> - begin match c.cl_constructor with - | None -> - fail rctx "Constructor not found" - | Some cf -> - cf - end - | FKNormal -> - begin try - PMap.find name (if fctx.is_static then c.cl_statics else c.cl_fields) - with Not_found -> - fail rctx "Field not found" - end - | FKInit -> - fail rctx "TODO" - in - pair_class_field rctx ctx cctx fctx cf cff p - ) d.d_data in - fl @ [fun () -> TypeloadFields.finalize_class ctx cctx] - -let pair_enums ctx rctx en d = - let ctx = { ctx with type_params = en.e_params } in - let rctx = {rctx with - print_stack = (Printf.sprintf "[Enum %s]" (s_type_path en.e_path)) :: rctx.print_stack - } in - List.iter (fun eff -> - let name = fst eff.ec_name in - let rctx = {rctx with - print_stack = (Printf.sprintf "[Field %s]" name) :: rctx.print_stack - } in - let ef = try - PMap.find name en.e_constrs - with Not_found -> - fail rctx "Field not found" - in - let th = pair_type eff.ec_type ef.ef_type in - ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false th)) - ) d.d_data; - [] - -let pair_typedefs ctx rctx td d = - let rctx = {rctx with - print_stack = (Printf.sprintf "[Typedef %s]" (s_type_path td.t_path)) :: rctx.print_stack - } in - let ctx = { ctx with type_params = td.t_params } in - ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false d.d_data)); - [] - -let pair_abstracts ctx rctx a d p = - let rctx = {rctx with - print_stack = (Printf.sprintf "[Abstract %s]" (s_type_path a.a_path)) :: rctx.print_stack - } in - match a.a_impl with - | Some c -> - c.cl_restore(); - let cctx = create_class_context c p in - let ctx = create_typer_context_for_class rctx.typer cctx p in - let fl = List.map (fun cff -> - let cff = TypeloadFields.transform_abstract_field2 ctx a cff in - let name = fst cff.cff_name in - let rctx = {rctx with - print_stack = (Printf.sprintf "[Field %s]" name) :: rctx.print_stack - } in - let display_modifier = Typeload.check_field_access ctx cff in - let fctx = create_field_context ctx cctx cff ctx.is_display_file display_modifier in - let cf = try - PMap.find name c.cl_statics - with Not_found -> - fail rctx "Field not found" - in - pair_class_field rctx ctx cctx fctx cf cff p - ) d.d_data in - fl @ [fun () -> TypeloadFields.finalize_class ctx cctx] - | None -> - (* ?*) - [] - -let attempt_retyping ctx m p = - let com = ctx.com in - let file,_,_,decls = TypeloadParse.parse_module' com m.m_path p in - let ctx = create_typer_context_for_module ctx m in - let rctx = { - typer = ctx; - print_stack = [Printf.sprintf "[Module %s]" (s_type_path m.m_path)]; - } in - (* log rctx 0 (Printf.sprintf "Retyping module %s" (s_type_path m.m_path)); *) - let find_type name = try - List.find (fun t -> snd (t_infos t).mt_path = name) ctx.m.curmod.m_types - with Not_found -> - fail rctx (Printf.sprintf "Type %s not found" name) - in - let rec loop acc decls = match decls with - | [] -> - List.rev acc - | (d,p) :: decls -> - begin match d with - | EImport (path,mode) -> - ImportHandling.init_import ctx path mode p; - ImportHandling.commit_import ctx path mode p; - loop acc decls - | EUsing path -> - ImportHandling.init_using ctx path p; - loop acc decls - | EClass c -> - let mt = find_type (fst c.d_name) in - loop ((d,mt) :: acc) decls - | EEnum en -> - let mt = find_type (fst en.d_name) in - loop ((d,mt) :: acc) decls - | ETypedef td -> - let mt = find_type (fst td.d_name) in - loop ((d,mt) :: acc) decls - | EAbstract a -> - let mt = find_type (fst a.d_name) in - loop ((d,mt) :: acc) decls - | _ -> - loop acc decls - end; - in - try - m.m_extra.m_cache_state <- MSUnknown; - let pairs = loop [] decls in - let fl = List.map (fun (d,mt) -> match d,mt with - | EClass d,TClassDecl c -> - pair_classes rctx c d p - | EEnum d,TEnumDecl en -> - pair_enums ctx rctx en d - | ETypedef d,TTypeDecl td -> - pair_typedefs ctx rctx td d - | EAbstract d,TAbstractDecl a -> - pair_abstracts ctx rctx a d p - | _ -> - fail rctx "?" - ) pairs in - (* If we get here we know that the everything is ok. *) - List.iter (fun fl -> - List.iter (fun f -> f()) fl - ) fl; - m.m_extra.m_cache_state <- MSGood; - m.m_extra.m_time <- Common.file_time file; - None - with Fail s -> - Some s diff --git a/src/compiler/server.ml b/src/compiler/server.ml index e9c061af69c..89939c1d175 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -353,20 +353,6 @@ let check_module sctx ctx m p = m.m_extra.m_cache_state <- MSUnknown; check () in - let dirty = match dirty with - | Some (DependencyDirty _) when has_policy Retype -> - let result = Retyper.attempt_retyping ctx m p in - begin match result with - | None -> - ServerMessage.retyper_ok com "" m; - None - | Some reason -> - ServerMessage.retyper_fail com "" m reason; - dirty - end - | _ -> - dirty - in (* Update the module now. It will use this dirty status for the remainder of this compilation. *) begin match dirty with | Some reason -> diff --git a/src/core/tType.ml b/src/core/tType.ml index 2ae0c85886b..faa40a8afba 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -30,7 +30,6 @@ type module_check_policy = | CheckFileContentModification | NoCheckDependencies | NoCheckShadowing - | Retype type module_tainting_reason = | CheckDisplayFile diff --git a/std/haxe/macro/CompilationServer.hx b/std/haxe/macro/CompilationServer.hx index 0cb50731bed..dbefb7ecdcf 100644 --- a/std/haxe/macro/CompilationServer.hx +++ b/std/haxe/macro/CompilationServer.hx @@ -52,10 +52,6 @@ enum abstract ModuleCheckPolicy(Int) { of the current module file. **/ var NoCheckShadowing = 3; - /** - Retype the module's contents if its file is invalidated. This is currently experimental. - **/ - var Retype = 4; } enum abstract ContextOptions(Int) { diff --git a/tests/server/src/cases/RetyperTests.hx b/tests/server/src/cases/RetyperTests.hx deleted file mode 100644 index 8a4db7a7140..00000000000 --- a/tests/server/src/cases/RetyperTests.hx +++ /dev/null @@ -1,203 +0,0 @@ -package cases; - -import haxe.display.FsPath; -import haxe.display.Server; -import utest.Assert; - -using StringTools; -using Lambda; - -class RetyperTests extends TestCase { - static function getBaseArgs(moduleName:String) { - return [ - moduleName + ".hx", - "--no-output", - "-js", - "no.js", - "--macro", - "haxe.macro.CompilationServer.setModuleCheckPolicy(['" + moduleName + "'], [Retype], false)" - ]; - } - - function testNonSignature() { - vfs.putContent("WithDependency.hx", getTemplate("WithDependency.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("WithDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('retyped WithDependency')); - } - - function testSignature() { - vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependency.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("WithSignatureDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping WithSignatureDependency')); - Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]')); - } - - function testSignatureInferredArg() { - vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyInferredArg.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("WithSignatureDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping WithSignatureDependency')); - Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]')); - } - - function testSignatureInferredRet() { - vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyInferredRet.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("WithSignatureDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping WithSignatureDependency')); - Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]')); - } - - function testSignatureVariable() { - vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyVariable.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("WithSignatureDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping WithSignatureDependency')); - Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]')); - } - - function testSignatureInferredVariable() { - vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyInferredVariable.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("WithSignatureDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping WithSignatureDependency')); - Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]')); - } - - function testSignatureProperty() { - vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyProperty.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("WithSignatureDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping WithSignatureDependency')); - Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]')); - } - - function testSignatureInferredProperty() { - vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyInferredProperty.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("WithSignatureDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping WithSignatureDependency')); - Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]')); - } - - function testMutual() { - vfs.putContent("WithMutualDependency.hx", getTemplate("retyper/WithMutualDependency.hx")); - vfs.putContent("MutualDependency.hx", getTemplate("retyper/MutualDependency.hx")); - var args = getBaseArgs("WithMutualDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MutualDependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('retyped WithMutualDependency')); - } - - function testParent() { - vfs.putContent("WithParentDependency.hx", getTemplate("retyper/WithParentDependency.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("WithParentDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping WithParentDependency')); - Assert.isTrue(hasMessage('[Module WithParentDependency] [Class WithParentDependency] [Relations]: Could not load [Module Dependency]')); - } - - function testInterface() { - vfs.putContent("WithInterfaceDependency.hx", getTemplate("retyper/WithInterfaceDependency.hx")); - vfs.putContent("InterfaceDependency.hx", getTemplate("retyper/InterfaceDependency.hx")); - var args = getBaseArgs("WithInterfaceDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("InterfaceDependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping WithInterfaceDependency')); - Assert.isTrue(hasMessage('[Module WithInterfaceDependency] [Class WithInterfaceDependency] [Relations]: Could not load [Module InterfaceDependency]')); - } - - function testIndependentEnum() { - vfs.putContent("IndependentEnum.hx", getTemplate("retyper/IndependentEnum.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("IndependentEnum"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('retyped IndependentEnum')); - } - - function testDependentEnum() { - vfs.putContent("DependentEnum.hx", getTemplate("retyper/DependentEnum.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("DependentEnum"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping DependentEnum')); - Assert.isTrue(hasMessage('[Module DependentEnum] [Enum DependentEnum] [Field Constructor]: Could not load [Module Dependency]')); - } - - function testIndependentTypedef() { - vfs.putContent("IndependentTypedef.hx", getTemplate("retyper/IndependentTypedef.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("IndependentTypedef"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('retyped IndependentTypedef')); - } - - function testDependentTypedef() { - vfs.putContent("DependentTypedef.hx", getTemplate("retyper/DependentTypedef.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("DependentTypedef"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping DependentTypedef')); - Assert.isTrue(hasMessage('[Module DependentTypedef] [Typedef DependentTypedef]: Could not load [Module Dependency]')); - } - - function testAbstractNonSignature() { - vfs.putContent("AbstractWithDependency.hx", getTemplate("retyper/AbstractWithDependency.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("AbstractWithDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('retyped AbstractWithDependency')); - } - - function testAbstractSignature() { - vfs.putContent("AbstractWithSignatureDependency.hx", getTemplate("retyper/AbstractWithSignatureDependency.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = getBaseArgs("AbstractWithSignatureDependency"); - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - Assert.isTrue(hasMessage('failed retyping AbstractWithSignatureDependency')); - Assert.isTrue(hasMessage('[Module AbstractWithSignatureDependency] [Abstract AbstractWithSignatureDependency] [Field test]: Could not load [Module Dependency]')); - } -} From caa3baa87edeef4acfd20431268c60aa1e027181 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 11 Jan 2024 06:33:17 +0100 Subject: [PATCH 085/184] [server] pull some changes from hxb branch --- src/compiler/server.ml | 89 +++++++++++---------- src/compiler/serverMessage.ml | 12 +-- src/core/ds/ring.ml | 15 ++++ tests/misc/java/projects/Issue10280/Main.hx | 5 +- tests/server/src/Main.hx | 2 +- tests/server/src/TestCase.hx | 7 +- 6 files changed, 76 insertions(+), 54 deletions(-) diff --git a/src/compiler/server.ml b/src/compiler/server.ml index 89939c1d175..c11b83060ff 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -225,27 +225,27 @@ let get_changed_directories sctx (ctx : Typecore.typer) = (* Checks if module [m] can be reused from the cache and returns None in that case. Otherwise, returns [Some m'] where [m'] is the module responsible for [m] not being reusable. *) -let check_module sctx ctx m p = +let check_module sctx ctx m_path m_extra p = let com = ctx.Typecore.com in let cc = CommonCache.get_cache com in - let content_changed m file = + let content_changed m_path file = let fkey = ctx.com.file_keys#get file in try let cfile = cc#find_file fkey in (* We must use the module path here because the file path is absolute and would cause positions in the parsed declarations to differ. *) - let new_data = TypeloadParse.parse_module ctx m.m_path p in + let new_data = TypeloadParse.parse_module ctx m_path p in cfile.c_decls <> snd new_data with Not_found -> true in - let check_module_shadowing paths m = + let check_module_shadowing paths m_path m_extra = List.iter (fun dir -> - let file = (dir.c_path ^ (snd m.m_path)) ^ ".hx" in + let file = (dir.c_path ^ (snd m_path)) ^ ".hx" in if Sys.file_exists file then begin let time = file_time file in - if time > m.m_extra.m_time then begin - ServerMessage.module_path_changed com "" (m,time,file); + if time > m_extra.m_time then begin + ServerMessage.module_path_changed com "" (m_path,m_extra,time,file); raise (Dirty (Shadowed file)) end end @@ -253,33 +253,33 @@ let check_module sctx ctx m p = in let start_mark = sctx.compilation_step in let unknown_state_modules = ref [] in - let rec check m = + let rec check m_path m_extra = let check_module_path () = let directories = get_changed_directories sctx ctx in - match m.m_extra.m_kind with + match m_extra.m_kind with | MFake | MImport -> () (* don't get classpath *) | MExtern -> (* if we have a file then this will override our extern type *) - check_module_shadowing directories m; + check_module_shadowing directories m_path m_extra; let rec loop = function | [] -> - if sctx.verbose then print_endline ("No library file was found for " ^ s_type_path m.m_path); (* TODO *) + if sctx.verbose then print_endline ("No library file was found for " ^ s_type_path m_path); (* TODO *) raise (Dirty LibraryChanged) | (file,load) :: l -> - match load m.m_path p with + match load m_path p with | None -> loop l | Some _ -> - if com.file_keys#get file <> (Path.UniqueKey.lazy_key m.m_extra.m_file) then begin - if sctx.verbose then print_endline ("Library file was changed for " ^ s_type_path m.m_path); (* TODO *) + if com.file_keys#get file <> (Path.UniqueKey.lazy_key m_extra.m_file) then begin + if sctx.verbose then print_endline ("Library file was changed for " ^ s_type_path m_path); (* TODO *) raise (Dirty LibraryChanged) end in loop com.load_extern_type | MCode -> - check_module_shadowing directories m + check_module_shadowing directories m_path m_extra | MMacro when com.is_macro_context -> - check_module_shadowing directories m + check_module_shadowing directories m_path m_extra | MMacro -> (* Creating another context while the previous one is incomplete means we have an infinite loop in the compiler. @@ -292,40 +292,43 @@ let check_module sctx ctx m p = ^ "Probably caused by shadowing a module of the standard library. " ^ "Make sure shadowed module does not pull macro context.")); let mctx = MacroContext.get_macro_context ctx in - check_module_shadowing (get_changed_directories sctx mctx) m + check_module_shadowing (get_changed_directories sctx mctx) m_path m_extra in - let has_policy policy = List.mem policy m.m_extra.m_check_policy || match policy with + let has_policy policy = List.mem policy m_extra.m_check_policy || match policy with | NoCheckShadowing | NoCheckFileTimeModification when !ServerConfig.do_not_check_modules && !Parser.display_mode <> DMNone -> true | _ -> false in let check_file () = - let file = Path.UniqueKey.lazy_path m.m_extra.m_file in - if file_time file <> m.m_extra.m_time then begin - if has_policy CheckFileContentModification && not (content_changed m file) then begin + let file = Path.UniqueKey.lazy_path m_extra.m_file in + if file_time file <> m_extra.m_time then begin + if has_policy CheckFileContentModification && not (content_changed m_path file) then begin ServerMessage.unchanged_content com "" file; end else begin - ServerMessage.not_cached com "" m; - if m.m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules (Path.UniqueKey.lazy_key m.m_extra.m_file); + ServerMessage.not_cached com "" m_path; + if m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules (Path.UniqueKey.lazy_key m_extra.m_file); raise (Dirty (FileChanged file)) end end in + let find_module_extra sign mpath = + ((com.cs#get_context sign)#find_module mpath).m_extra + in let check_dependencies () = PMap.iter (fun _ (sign,mpath) -> - let m2 = try - (com.cs#get_context sign)#find_module mpath + let m2_extra = try + find_module_extra sign mpath with Not_found -> - die (Printf.sprintf "Could not find dependency %s of %s in the cache" (s_type_path mpath) (s_type_path m.m_path)) __LOC__; + die (Printf.sprintf "Could not find dependency %s of %s in the cache" (s_type_path mpath) (s_type_path m_path)) __LOC__; in - match check m2 with + match check mpath m2_extra with | None -> () - | Some reason -> raise (Dirty (DependencyDirty(m2.m_path,reason))) - ) m.m_extra.m_deps; + | Some reason -> raise (Dirty (DependencyDirty(mpath,reason))) + ) m_extra.m_deps; in let check () = try if not (has_policy NoCheckShadowing) then check_module_path(); - if not (has_policy NoCheckFileTimeModification) || Path.file_extension (Path.UniqueKey.lazy_path m.m_extra.m_file) <> "hx" then check_file(); + if not (has_policy NoCheckFileTimeModification) || Path.file_extension (Path.UniqueKey.lazy_path m_extra.m_file) <> "hx" then check_file(); if not (has_policy NoCheckDependencies) then check_dependencies(); None with @@ -333,15 +336,15 @@ let check_module sctx ctx m p = Some reason in (* If the module mark matches our compilation mark, we are done *) - if m.m_extra.m_checked = start_mark then begin match m.m_extra.m_cache_state with + if m_extra.m_checked = start_mark then begin match m_extra.m_cache_state with | MSGood | MSUnknown -> None | MSBad reason -> Some reason end else begin (* Otherwise, set to current compilation mark for recursion *) - m.m_extra.m_checked <- start_mark; - let dirty = match m.m_extra.m_cache_state with + m_extra.m_checked <- start_mark; + let dirty = match m_extra.m_cache_state with | MSBad reason -> (* If we are already dirty, stick to it. *) Some reason @@ -350,35 +353,35 @@ let check_module sctx ctx m p = die "" __LOC__ | MSGood -> (* Otherwise, run the checks *) - m.m_extra.m_cache_state <- MSUnknown; + m_extra.m_cache_state <- MSUnknown; check () in (* Update the module now. It will use this dirty status for the remainder of this compilation. *) begin match dirty with | Some reason -> (* Update the state if we're dirty. *) - m.m_extra.m_cache_state <- MSBad reason; + m_extra.m_cache_state <- MSBad reason; | None -> (* We cannot update if we're clean because at this point it might just be an assumption. Instead We add the module to a list which is updated at the end of handling this subgraph. *) - unknown_state_modules := m :: !unknown_state_modules; + unknown_state_modules := m_extra :: !unknown_state_modules; end; dirty end in - let state = check m in + let state = check m_path m_extra in begin match state with | None -> (* If the entire subgraph is clean, we can set all modules to good state *) - List.iter (fun m -> m.m_extra.m_cache_state <- MSGood) !unknown_state_modules; + List.iter (fun m_extra -> m_extra.m_cache_state <- MSGood) !unknown_state_modules; | Some _ -> (* Otherwise, unknown state module may or may not be dirty. We didn't check everything eagerly, so we have to make sure that the module is checked again if it appears in a different check. This is achieved by setting m_checked to a lower value and assuming Good state again. *) - List.iter (fun m -> match m.m_extra.m_cache_state with + List.iter (fun m_extra -> match m_extra.m_cache_state with | MSUnknown -> - m.m_extra.m_checked <- start_mark - 1; - m.m_extra.m_cache_state <- MSGood; + m_extra.m_checked <- start_mark - 1; + m_extra.m_cache_state <- MSGood; | MSGood | MSBad _ -> () ) !unknown_state_modules @@ -431,10 +434,10 @@ let type_module sctx (ctx:Typecore.typer) mpath p = try let m = cc#find_module mpath in let tcheck = Timer.timer ["server";"module cache";"check"] in - begin match check_module sctx ctx m p with + begin match check_module sctx ctx m.m_path m.m_extra p with | None -> () | Some reason -> - ServerMessage.skipping_dep com "" (m,(Printer.s_module_skip_reason reason)); + ServerMessage.skipping_dep com "" (m.m_path,(Printer.s_module_skip_reason reason)); tcheck(); raise Not_found; end; diff --git a/src/compiler/serverMessage.ml b/src/compiler/serverMessage.ml index 18a3faeeefa..e82930c08bc 100644 --- a/src/compiler/serverMessage.ml +++ b/src/compiler/serverMessage.ml @@ -75,12 +75,12 @@ let found_directories com tabs dirs = let changed_directories com tabs dirs = if config.print_changed_directories then print_endline (Printf.sprintf "%schanged directories: [%s]" (sign_string com) (String.concat ", " (List.map (fun dir -> "\"" ^ dir.c_path ^ "\"") dirs))) -let module_path_changed com tabs (m,time,file) = +let module_path_changed com tabs (m_path,m_extra,time,file) = if config.print_module_path_changed then print_endline (Printf.sprintf "%smodule path might have changed: %s\n\twas: %2.0f %s\n\tnow: %2.0f %s" - (sign_string com) (s_type_path m.m_path) m.m_extra.m_time (Path.UniqueKey.lazy_path m.m_extra.m_file) time file) + (sign_string com) (s_type_path m_path) m_extra.m_time (Path.UniqueKey.lazy_path m_extra.m_file) time file) -let not_cached com tabs m = - if config.print_not_cached then print_endline (Printf.sprintf "%s%s not cached (%s)" (sign_string com) (s_type_path m.m_path) "modified") +let not_cached com tabs m_path = + if config.print_not_cached then print_endline (Printf.sprintf "%s%s not cached (%s)" (sign_string com) (s_type_path m_path) "modified") let parsed com tabs (ffile,info) = if config.print_parsed then print_endline (Printf.sprintf "%sparsed %s (%s)" (sign_string com) ffile info) @@ -100,8 +100,8 @@ let retyper_fail com tabs m reason = print_endline (Printf.sprintf "%s%s%s" (sign_string com) (tabs ^ " ") reason); end -let skipping_dep com tabs (m,reason) = - if config.print_skipping_dep then print_endline (Printf.sprintf "%sskipping %s (%s)" (sign_string com) (s_type_path m.m_path) reason) +let skipping_dep com tabs (mpath,reason) = + if config.print_skipping_dep then print_endline (Printf.sprintf "%sskipping %s (%s)" (sign_string com) (s_type_path mpath) reason) let unchanged_content com tabs file = if config.print_unchanged_content then print_endline (Printf.sprintf "%s%s changed time not but content, reusing" (sign_string com) file) diff --git a/src/core/ds/ring.ml b/src/core/ds/ring.ml index a98e7a59529..4ec861f727d 100644 --- a/src/core/ds/ring.ml +++ b/src/core/ds/ring.ml @@ -39,6 +39,21 @@ let fold r acc f = in loop 0 acc +let find r f = + let len = Array.length r.values in + let rec loop i = + if i = len then + raise Not_found + else begin + let v = r.values.(i) in + if f v then + v + else + loop (i + 1) + end + in + loop 0 + let is_filled r = r.num_filled >= Array.length r.values diff --git a/tests/misc/java/projects/Issue10280/Main.hx b/tests/misc/java/projects/Issue10280/Main.hx index 14bcefb7483..bf2044f98e2 100644 --- a/tests/misc/java/projects/Issue10280/Main.hx +++ b/tests/misc/java/projects/Issue10280/Main.hx @@ -29,12 +29,11 @@ class OldClass { public function new() {} } ); - - Compiler.exclude('OldClass'); - defined = true; }); + Context.onGenerate(_ -> Compiler.exclude('OldClass')); + return null; } } \ No newline at end of file diff --git a/tests/server/src/Main.hx b/tests/server/src/Main.hx index 77aa51ba3a0..e35a4cafcbe 100644 --- a/tests/server/src/Main.hx +++ b/tests/server/src/Main.hx @@ -13,4 +13,4 @@ class Main { report.displaySuccessResults = NeverShowSuccessResults; runner.run(); } -} +} \ No newline at end of file diff --git a/tests/server/src/TestCase.hx b/tests/server/src/TestCase.hx index 621dd1702bf..0d4b9d3a283 100644 --- a/tests/server/src/TestCase.hx +++ b/tests/server/src/TestCase.hx @@ -120,7 +120,12 @@ class TestCase implements ITest { errorMessages = []; server.rawRequest(args, null, function(result) { handleResult(result); - callback(Json.parse(result.stderr).result.result); + var json = Json.parse(result.stderr); + if (json.result != null) { + callback(json.result.result); + } else { + sendErrorMessage('Error: ' + json.error); + } done(); }, function(msg) { sendErrorMessage(msg); From cf2a77b4066874dffa38656177e3ead277076e07 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 11 Jan 2024 06:33:29 +0100 Subject: [PATCH 086/184] [jvm] factor out zip output --- src/core/zip_output.ml | 18 ++++++++++++++++++ src/generators/genjvm.ml | 25 +++---------------------- 2 files changed, 21 insertions(+), 22 deletions(-) create mode 100644 src/core/zip_output.ml diff --git a/src/core/zip_output.ml b/src/core/zip_output.ml new file mode 100644 index 00000000000..c2bf513d49d --- /dev/null +++ b/src/core/zip_output.ml @@ -0,0 +1,18 @@ +class virtual any_output = object(self) + method virtual add_entry : string -> string -> unit + method virtual close : unit +end + +class zip_output + (zip_path : string) + (compression_level : int) += object(self) + inherit any_output + val zip = Zip.open_out zip_path + + method add_entry (content : string) (name : string) = + Zip.add_entry ~level:compression_level content zip name + + method close = + Zip.close_out zip +end \ No newline at end of file diff --git a/src/generators/genjvm.ml b/src/generators/genjvm.ml index 657c594be02..158306a5079 100644 --- a/src/generators/genjvm.ml +++ b/src/generators/genjvm.ml @@ -50,16 +50,11 @@ let get_construction_mode c cf = if Meta.has Meta.HxGen cf.cf_meta then ConstructInitPlusNew else ConstructInit -class virtual jvm_output = object(self) - method virtual add_entry : string -> string -> unit - method virtual close : unit -end - (* Haxe *) type generation_context = { com : Common.context; - out : jvm_output; + out : Zip_output.any_output; t_runtime_exception : Type.t; entry_point : (tclass * texpr) option; t_exception : Type.t; @@ -109,24 +104,10 @@ let run_timed gctx detail name f = sub#run_finally f (fun () -> gctx.timer <- old) end -class jar_output - (jar_path : string) - (compression_level : int) -= object(self) - inherit jvm_output - val jar = Zip.open_out jar_path - - method add_entry (content : string) (name : string) = - Zip.add_entry ~level:compression_level content jar name - - method close = - Zip.close_out jar -end - class file_output (base_path : string) = object(self) - inherit jvm_output + inherit Zip_output.any_output method add_entry (content : string) (name : string) = let path = base_path ^ name in @@ -3031,7 +3012,7 @@ let generate jvm_flag com = in if compression_level < 0 || compression_level > 9 then failwith "Invalid value for -D jvm.compression-level: Must be >=0 and <= 9"; let create_jar path = - new jar_output path compression_level + new Zip_output.zip_output path compression_level in let out_dir,out = if jvm_flag then begin match path.file_name with From 074077e53c8bef41dcd0dd49908106487e91fbe0 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 11 Jan 2024 06:35:49 +0100 Subject: [PATCH 087/184] [compiler] split up native lib handling --- src/compiler/compiler.ml | 16 +++++++++------- src/compiler/serverCompilationContext.ml | 2 ++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/compiler/compiler.ml b/src/compiler/compiler.ml index 9e9b61dc6f8..da967e5fcc7 100644 --- a/src/compiler/compiler.ml +++ b/src/compiler/compiler.ml @@ -162,7 +162,13 @@ module Setup = struct add_std "eval"; "eval" - let create_typer_context ctx macros native_libs = + let init_native_libs com native_libs = + (* Native lib pass 1: Register *) + let fl = List.map (fun lib -> NativeLibraryHandler.add_native_lib com lib) (List.rev native_libs) in + (* Native lib pass 2: Initialize *) + List.iter (fun f -> f()) fl + + let create_typer_context ctx macros = let com = ctx.com in Common.log com ("Classpath: " ^ (String.concat ";" com.class_path)); let buffer = Buffer.create 64 in @@ -174,10 +180,6 @@ module Setup = struct Buffer.truncate buffer (Buffer.length buffer - 1); Common.log com (Buffer.contents buffer); com.callbacks#run com.error_ext com.callbacks#get_before_typer_create; - (* Native lib pass 1: Register *) - let fl = List.map (fun lib -> NativeLibraryHandler.add_native_lib com lib) (List.rev native_libs) in - (* Native lib pass 2: Initialize *) - List.iter (fun f -> f()) fl; TyperEntry.create com macros let executable_path() = @@ -279,7 +281,6 @@ let do_type ctx mctx actx display_file_dot_path macro_cache_enabled = CommonCache.maybe_add_context_sign cs com "before_init_macros"; enter_stage com CInitMacrosStart; ServerMessage.compiler_stage com; - let mctx = List.fold_left (fun mctx path -> Some (MacroContext.call_init_macro ctx.com mctx path) ) mctx (List.rev actx.config_macros) in @@ -288,7 +289,8 @@ let do_type ctx mctx actx display_file_dot_path macro_cache_enabled = MacroContext.macro_enable_cache := macro_cache_enabled; let macros = match mctx with None -> None | Some mctx -> mctx.g.macros in - let tctx = Setup.create_typer_context ctx macros actx.native_libs in + Setup.init_native_libs com actx.native_libs; + let tctx = Setup.create_typer_context ctx macros in let display_file_dot_path = DisplayProcessing.maybe_load_display_file_before_typing tctx display_file_dot_path in check_defines ctx.com; CommonCache.lock_signature com "after_init_macros"; diff --git a/src/compiler/serverCompilationContext.ml b/src/compiler/serverCompilationContext.ml index d0c87099acd..479ae5c768f 100644 --- a/src/compiler/serverCompilationContext.ml +++ b/src/compiler/serverCompilationContext.ml @@ -59,7 +59,9 @@ let reset sctx = let maybe_cache_context sctx com = if com.display.dms_full_typing && com.display.dms_populate_cache then begin + let t = Timer.timer ["server";"cache context"] in CommonCache.cache_context sctx.cs com; + t(); ServerMessage.cached_modules com "" (List.length com.modules); end From 3c07ce1569df6daf03a4fa4a8ab520af5273759a Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 11 Jan 2024 06:46:10 +0100 Subject: [PATCH 088/184] [generic] make type parameter cloning more accurate --- src/context/common.ml | 1 + src/context/typecore.ml | 12 +++++++++++ src/typing/generic.ml | 43 ++++++++++++++++++++++++++++++---------- src/typing/typerEntry.ml | 5 ++++- 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/context/common.ml b/src/context/common.ml index 89d0444e83d..fe49741dcb4 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -890,6 +890,7 @@ let clone com is_macro_context = { com with cache = None; basic = { t with + tvoid = mk_mono(); tint = mk_mono(); tfloat = mk_mono(); tbool = mk_mono(); diff --git a/src/context/typecore.ml b/src/context/typecore.ml index 1d5ac7e250d..911d4270099 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -506,6 +506,18 @@ let is_forced_inline c cf = let needs_inline ctx c cf = cf.cf_kind = Method MethInline && ctx.allow_inline && (ctx.g.doinline || is_forced_inline c cf) +let clone_type_parameter map path ttp = + let c = ttp.ttp_class in + let c = {c with cl_path = path} in + let def = Option.map map ttp.ttp_default in + let constraints = match ttp.ttp_constraints with + | None -> None + | Some constraints -> Some (lazy (List.map map (Lazy.force constraints))) + in + let ttp' = mk_type_param c ttp.ttp_host def constraints in + c.cl_kind <- KTypeParameter ttp'; + ttp' + (** checks if we can access to a given class field using current context *) let can_access ctx c cf stat = if (has_class_field_flag cf CfPublic) then diff --git a/src/typing/generic.ml b/src/typing/generic.ml index 2c34510de40..90ba146a894 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -231,6 +231,10 @@ let build_instances ctx t p = in loop t +let clone_type_parameter gctx mg path ttp = + let ttp = clone_type_parameter (generic_substitute_type gctx) path ttp in + ttp.ttp_class.cl_module <- mg; + ttp let build_generic_class ctx c p tl = let pack = fst c.cl_path in @@ -309,14 +313,7 @@ let build_generic_class ctx c p tl = set_type_parameter_dependencies mg tl; let build_field cf_old = let params = List.map (fun ttp -> - let c = {ttp.ttp_class with cl_module = mg} in - let def = Option.map (generic_substitute_type gctx) ttp.ttp_default in - let constraints = match ttp.ttp_constraints with - | None -> None - | Some constraints -> Some (lazy (List.map (generic_substitute_type gctx) (Lazy.force constraints))) - in - let ttp' = mk_type_param c ttp.ttp_host def constraints in - c.cl_kind <- KTypeParameter ttp'; + let ttp' = clone_type_parameter gctx mg ([cf_old.cf_name],ttp.ttp_name) ttp in (ttp.ttp_type,ttp') ) cf_old.cf_params in let param_subst = List.map (fun (t,ttp) -> t,(ttp.ttp_type,None)) params in @@ -409,6 +406,17 @@ let build_generic_class ctx c p tl = TInst (cg,[]) end +let extract_type_parameters tl = + let params = DynArray.create () in + let rec loop t = match follow t with + | TInst({cl_kind = KTypeParameter ttp},[]) -> + DynArray.add params ttp; + | _ -> + TFunctions.iter loop t + in + List.iter loop tl; + DynArray.to_list params + let type_generic_function ctx fa fcc with_type p = let c,stat = match fa.fa_host with | FHInstance(c,tl) -> c,false @@ -432,8 +440,18 @@ let type_generic_function ctx fa fcc with_type p = ) monos; let el = fcc.fc_args in let gctx = make_generic ctx cf.cf_params monos (Meta.has (Meta.Custom ":debug.generic") cf.cf_meta) p in - let fc_type = build_instances ctx fcc.fc_type p in let name = cf.cf_name ^ "_" ^ gctx.name in + let params = extract_type_parameters monos in + let clones = List.map (fun ttp -> + let name_path = if (fst ttp.ttp_class.cl_path) = [cf.cf_name] then ([name],ttp.ttp_name) else ttp.ttp_class.cl_path in + clone_type_parameter gctx c.cl_module name_path ttp + ) params in + let param_subst = List.map2 (fun ttp ttp' -> + (ttp.ttp_type,ttp') + ) params clones in + let param_subst = List.map (fun (t,ttp) -> t,(ttp.ttp_type,None)) param_subst in + let gctx = {gctx with subst = param_subst @ gctx.subst} in + let fc_type = build_instances ctx (generic_substitute_type gctx fcc.fc_type) p in let unify_existing_field tcf pcf = try unify_raise tcf fc_type p with Error ({ err_message = Unify _; err_depth = depth } as err) -> @@ -484,7 +502,12 @@ let type_generic_function ctx fa fcc with_type p = ); cf2.cf_kind <- cf.cf_kind; if not (has_class_field_flag cf CfPublic) then remove_class_field_flag cf2 CfPublic; - cf2.cf_meta <- (Meta.NoCompletion,[],p) :: (Meta.NoUsing,[],p) :: (Meta.GenericInstance,[],p) :: cf.cf_meta + let meta = List.filter (fun (meta,_,_) -> match meta with + | Meta.Generic -> false + | _ -> true + ) cf.cf_meta in + cf2.cf_meta <- (Meta.NoCompletion,[],p) :: (Meta.NoUsing,[],p) :: (Meta.GenericInstance,[],p) :: meta; + cf2.cf_params <- clones in let mk_cf2 name = mk_field ~static:stat name fc_type cf.cf_pos cf.cf_name_pos diff --git a/src/typing/typerEntry.ml b/src/typing/typerEntry.ml index 0a57a36f729..096f5d7b2f0 100644 --- a/src/typing/typerEntry.ml +++ b/src/typing/typerEntry.ml @@ -90,7 +90,10 @@ let create com macros = match t with | TAbstractDecl a -> (match snd a.a_path with - | "Void" -> ctx.t.tvoid <- TAbstract (a,[]); + | "Void" -> + let t = TAbstract (a,[]) in + Type.unify t ctx.t.tvoid; + ctx.t.tvoid <- t; | "Float" -> let t = (TAbstract (a,[])) in Type.unify t ctx.t.tfloat; From 58e9e5245bf727a89c04de5b68b213a0fb50921a Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 11 Jan 2024 07:01:53 +0100 Subject: [PATCH 089/184] [typer] rework unify_anons --- src/core/tUnification.ml | 101 +++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 37 deletions(-) diff --git a/src/core/tUnification.ml b/src/core/tUnification.ml index 25bad0a5f81..055c1ecf562 100644 --- a/src/core/tUnification.ml +++ b/src/core/tUnification.ml @@ -338,6 +338,13 @@ let fast_eq_check type_param_check a b = c1 == c2 && List.for_all2 type_param_check l1 l2 | TAbstract (a1,l1), TAbstract (a2,l2) -> a1 == a2 && List.for_all2 type_param_check l1 l2 + | TAnon an1,TAnon an2 -> + begin match !(an1.a_status),!(an2.a_status) with + | ClassStatics c, ClassStatics c2 -> c == c2 + | EnumStatics e, EnumStatics e2 -> e == e2 + | AbstractStatics a, AbstractStatics a2 -> a == a2 + | _ -> false + end | _ , _ -> false @@ -386,9 +393,6 @@ let rec shallow_eq a b = loop (List.sort sort_compare fields1) (List.sort sort_compare fields2) in (match !(a2.a_status), !(a1.a_status) with - | ClassStatics c, ClassStatics c2 -> c == c2 - | EnumStatics e, EnumStatics e2 -> e == e2 - | AbstractStatics a, AbstractStatics a2 -> a == a2 | Extend tl1, Extend tl2 -> fields_eq() && List.for_all2 shallow_eq tl1 tl2 | Closed, Closed -> fields_eq() | Const, Const -> fields_eq() @@ -565,6 +569,10 @@ let rec type_eq uctx a b = | AbstractStatics a -> (match !(a1.a_status) with AbstractStatics a2 when a == a2 -> () | _ -> error []) | _ -> () ); + let fields = match !(a1.a_status) with + | ClassStatics c -> c.cl_statics + | _ -> a1.a_fields + in PMap.iter (fun n f1 -> try let f2 = PMap.find n a2.a_fields in @@ -575,9 +583,9 @@ let rec type_eq uctx a b = with Not_found -> error [has_no_field b n]; - ) a1.a_fields; + ) fields; PMap.iter (fun n f2 -> - if not (PMap.mem n a1.a_fields) then begin + if not (PMap.mem n fields) then begin error [has_no_field a n]; end; ) a2.a_fields; @@ -897,39 +905,58 @@ let rec unify (uctx : unification_context) a b = error [cannot_unify a b] and unify_anons uctx a b a1 a2 = - (try - PMap.iter (fun n f2 -> + let unify_field a1_fields f2 = + let n = f2.cf_name in + let f1 = PMap.find n a1_fields in + if not (unify_kind f1.cf_kind f2.cf_kind) then + error [invalid_kind n f1.cf_kind f2.cf_kind]; + if (has_class_field_flag f2 CfPublic) && not (has_class_field_flag f1 CfPublic) then + error [invalid_visibility n]; try - let f1 = PMap.find n a1.a_fields in - if not (unify_kind f1.cf_kind f2.cf_kind) then - error [invalid_kind n f1.cf_kind f2.cf_kind]; - if (has_class_field_flag f2 CfPublic) && not (has_class_field_flag f1 CfPublic) then error [invalid_visibility n]; - try - let f1_type = - if fast_eq f1.cf_type f2.cf_type then f1.cf_type - else field_type f1 - in - unify_with_access uctx f1 f1_type f2; - (match !(a1.a_status) with - | ClassStatics c when not (Meta.has Meta.MaybeUsed f1.cf_meta) -> f1.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: f1.cf_meta - | _ -> ()); - with - Unify_error l -> error (invalid_field n :: l) - with - Not_found -> - match !(a1.a_status) with - | Const when Meta.has Meta.Optional f2.cf_meta -> - a1.a_fields <- PMap.add f2.cf_name f2 a1.a_fields - | _ -> - error [has_no_field a n]; - ) a2.a_fields; - (match !(a2.a_status) with - | ClassStatics c -> (match !(a1.a_status) with ClassStatics c2 when c == c2 -> () | _ -> error []) - | EnumStatics e -> (match !(a1.a_status) with EnumStatics e2 when e == e2 -> () | _ -> error []) - | AbstractStatics a -> (match !(a1.a_status) with AbstractStatics a2 when a == a2 -> () | _ -> error []) - | Const | Extend _ | Closed -> ()) - with - Unify_error l -> error (cannot_unify a b :: l)) + let f1_type = + if fast_eq f1.cf_type f2.cf_type then f1.cf_type + else field_type f1 + in + unify_with_access uctx f1 f1_type f2; + f1 + with Unify_error l -> + error (invalid_field n :: l) + in + let unify_fields a1_fields f_good f_bad = + try + PMap.iter (fun _ f2 -> + try + f_good (unify_field a1_fields f2) + with Not_found -> + if not (f_bad f2) then + error [has_no_field a f2.cf_name] + ) a2.a_fields + with Unify_error l -> + error (cannot_unify a b :: l) + in + begin match !(a1.a_status),!(a2.a_status) with + | ClassStatics c1,ClassStatics c2 when c1 == c2 -> + () + | EnumStatics en1,EnumStatics en2 when en1 == en2 -> + () + | AbstractStatics a1,AbstractStatics a2 when a1 == a2 -> + () + | Const,_ -> + unify_fields a1.a_fields (fun _ -> ()) (fun f2 -> + if Meta.has Meta.Optional f2.cf_meta then begin + a1.a_fields <- PMap.add f2.cf_name f2 a1.a_fields; + true + end else + false + ) + | ClassStatics c1,_ -> + unify_fields c1.cl_statics (fun f1 -> + if not (Meta.has Meta.MaybeUsed f1.cf_meta) then + f1.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: f1.cf_meta + ) (fun _ -> false) + | _ -> + unify_fields a1.a_fields (fun _ -> ()) (fun _ -> false) + end and does_func_unify f = try f(); true with Unify_error _ -> false From dec37b31a0af73de9ec59db040ce73e6cc37b345 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 11 Jan 2024 08:42:55 +0100 Subject: [PATCH 090/184] [libs] delete things randomly --- libs/Makefile | 3 +- libs/ocamake/ocamake.dsp | 66 ---- libs/ocamake/ocamake.dsw | 29 -- libs/ocamake/ocamake.html | 94 ----- libs/ocamake/ocamake.ml | 661 ------------------------------- libs/swflib/swflib.sln | 21 - libs/swflib/swflib.vcproj | 80 ---- libs/ttflib/Makefile | 31 -- libs/ttflib/dune | 14 - libs/ttflib/main.ml | 139 ------- libs/ttflib/tTFCanvasWriter.ml | 50 --- libs/ttflib/tTFData.ml | 360 ----------------- libs/ttflib/tTFJsonWriter.ml | 49 --- libs/ttflib/tTFParser.ml | 688 --------------------------------- libs/ttflib/tTFSwfWriter.ml | 211 ---------- libs/ttflib/tTFTools.ml | 275 ------------- src/dune | 2 +- src/generators/genswf.ml | 55 --- 18 files changed, 2 insertions(+), 2826 deletions(-) delete mode 100644 libs/ocamake/ocamake.dsp delete mode 100644 libs/ocamake/ocamake.dsw delete mode 100644 libs/ocamake/ocamake.html delete mode 100644 libs/ocamake/ocamake.ml delete mode 100644 libs/swflib/swflib.sln delete mode 100644 libs/swflib/swflib.vcproj delete mode 100644 libs/ttflib/Makefile delete mode 100644 libs/ttflib/dune delete mode 100644 libs/ttflib/main.ml delete mode 100644 libs/ttflib/tTFCanvasWriter.ml delete mode 100644 libs/ttflib/tTFData.ml delete mode 100644 libs/ttflib/tTFJsonWriter.ml delete mode 100644 libs/ttflib/tTFParser.ml delete mode 100644 libs/ttflib/tTFSwfWriter.ml delete mode 100644 libs/ttflib/tTFTools.ml diff --git a/libs/Makefile b/libs/Makefile index d0b240a9d64..09637139c63 100644 --- a/libs/Makefile +++ b/libs/Makefile @@ -1,7 +1,7 @@ OCAMLOPT = ocamlopt OCAMLC = ocamlc TARGET_FLAG = all -LIBS=extlib-leftovers extc neko javalib ilib swflib ttflib objsize pcre2 ziplib +LIBS=extlib-leftovers extc neko javalib ilib swflib objsize pcre2 ziplib all: $(LIBS) $(LIBS): @@ -14,7 +14,6 @@ clean: $(MAKE) -C javalib clean $(MAKE) -C ilib clean $(MAKE) -C swflib clean - $(MAKE) -C ttflib clean $(MAKE) -C objsize clean $(MAKE) -C pcre2 clean $(MAKE) -C ziplib clean diff --git a/libs/ocamake/ocamake.dsp b/libs/ocamake/ocamake.dsp deleted file mode 100644 index 461ebd15741..00000000000 --- a/libs/ocamake/ocamake.dsp +++ /dev/null @@ -1,66 +0,0 @@ -# Microsoft Developer Studio Project File - Name="ocamake" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) External Target" 0x0106 - -CFG=ocamake - Win32 Native code -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "ocamake.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "ocamake.mak" CFG="ocamake - Win32 Native code" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "ocamake - Win32 Native code" (based on "Win32 (x86) External Target") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "" -# PROP BASE Intermediate_Dir "" -# PROP BASE Cmd_Line "ocamake -opt ocamake.dsp -o ocamake.exe" -# PROP BASE Rebuild_Opt "-all" -# PROP BASE Target_File "ocamake_opt.exe" -# PROP BASE Bsc_Name "" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "" -# PROP Intermediate_Dir "" -# PROP Cmd_Line "ocamake str.cmxa unix.cmxa -opt ocamake.dsp -o ocadbg.exe" -# PROP Rebuild_Opt "-all" -# PROP Target_File "ocadbg.exe" -# PROP Bsc_Name "" -# PROP Target_Dir "" -# Begin Target - -# Name "ocamake - Win32 Native code" - -!IF "$(CFG)" == "ocamake - Win32 Native code" - -!ENDIF - -# Begin Group "ML Files" - -# PROP Default_Filter "ml;mly;mll" -# Begin Source File - -SOURCE=.\ocamake.ml -# End Source File -# End Group -# Begin Group "MLI Files" - -# PROP Default_Filter "mli" -# End Group -# End Target -# End Project diff --git a/libs/ocamake/ocamake.dsw b/libs/ocamake/ocamake.dsw deleted file mode 100644 index 620f4514a98..00000000000 --- a/libs/ocamake/ocamake.dsw +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "ocamake"=.\ocamake.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/libs/ocamake/ocamake.html b/libs/ocamake/ocamake.html deleted file mode 100644 index 9af8925b504..00000000000 --- a/libs/ocamake/ocamake.html +++ /dev/null @@ -1,94 +0,0 @@ - - -
OCamake
-
- - OCamake - Copyright (c)2002-2003 Nicolas Cannasse & Motion Twin.
- The last version of this software can be found at : http://tech.motion-twin.com

- This software is provided "AS IS" without any warranty of any kind, merchantability or fitness for a particular purpose. You should use it at your own risks, as the author and his company won't be responsible for any problem that the usage of this software could raise. -
-
-
- -