diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 71c8b10b990..a55d3932cb6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -335,6 +335,7 @@ jobs: run: echo "branch=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT - name: Build xmldoc + if: matrix.ocaml == '4.08.1' run: | set -ex make -s xmldoc @@ -615,7 +616,7 @@ jobs: - name: Install dependencies env: # For compatibility with macOS 10.13 - ZLIB_VERSION: 1.3 + ZLIB_VERSION: 1.3.1 MBEDTLS_VERSION: 2.28.5 PCRE2_VERSION: 10.42 run: | @@ -631,7 +632,7 @@ jobs: brew install cpanminus cpanm IPC::System::Simple cpanm String::ShellQuote - curl -L https://www.zlib.net/zlib-$ZLIB_VERSION.tar.gz | tar xz + curl -L https://github.com/madler/zlib/releases/download/v$ZLIB_VERSION/zlib-$ZLIB_VERSION.tar.gz | tar xz cd zlib-$ZLIB_VERSION ./configure make && make install diff --git a/extra/CHANGES.txt b/extra/CHANGES.txt index a1ca8221f44..42bd5b671c7 100644 --- a/extra/CHANGES.txt +++ b/extra/CHANGES.txt @@ -1,3 +1,34 @@ +2024-03-04 4.3.4 + + General improvements: + + all : allow @:using with Class and Enum (#11553) + display : expose list of metadata/defines (#11399) + + Bugfixes: + + all : typedef vs. GADT (#11446) + all : don't double-throw exceptions (#11175) + all : fix some abstract inlining failures (#11526) + all : fix JsonPrinter empty parent class (#11560) + all : dce: clean up operator handling (#11427) + all : analyzer: deal with unreachable block in binops (#11402) + all : analyzer: don't recursively check enum values when const propagating (#11429) + all : analyzer: fix check for inlined purity meta + display : fix errors from parser missing in diagnostics (#8687) + display : fix display services with static extension (#11285) + display : fix display services with safe navigation (#11205) + hl : hlopt rework try-catch control flow (#11581) + hl/c : fix reserved keywords (#11408) + + Deprecation / future version handling: + + all : don't infer string on concat, when using -D haxe-next (#11318) + all : handle optional arguments with bind, when using -D haxe-next (#11533) + macro : build order vs inheritance, when using -D haxe-next (#11582) + macro : deprecate some API from haxe.macro.Compiler (see #11540) + java/jvm : warn about --java ... -D jvm vs --jvm ... + 2023-09-17 4.3.3 General improvements: diff --git a/haxe.opam b/haxe.opam index e370c420337..b1b90ac2987 100644 --- a/haxe.opam +++ b/haxe.opam @@ -1,6 +1,6 @@ opam-version: "2.0" name: "haxe" -version: "4.3.3" +version: "4.3.4" synopsis: "Multi-target universal programming language" description: """ Haxe is an open source toolkit based on a modern, @@ -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"} @@ -32,5 +32,5 @@ depends: [ "conf-libpcre2-8" "conf-zlib" "conf-neko" - "luv" + "luv" {= "0.5.12"} ] diff --git a/src-prebuild/prebuild.ml b/src-prebuild/prebuild.ml index 62e01c6f146..8b99802a811 100644 --- a/src-prebuild/prebuild.ml +++ b/src-prebuild/prebuild.ml @@ -286,6 +286,18 @@ let parse_meta_usage = function | \"TVariable\" -> TVariable | t -> raise (failwith (\"invalid metadata target \" ^ t)) +let print_meta_usage = function + | TClass -> \"TClass\" + | TClassField -> \"TClassField\" + | TAbstract -> \"TAbstract\" + | TAbstractField -> \"TAbstractField\" + | TEnum -> \"TEnum\" + | TTypedef -> \"TTypedef\" + | TAnyField -> \"TAnyField\" + | TExpr -> \"TExpr\" + | TTypeParameter -> \"TTypeParameter\" + | TVariable -> \"TVariable\" + type meta_parameter = | HasParam of string | Platforms of platform list diff --git a/src/compiler/args.ml b/src/compiler/args.ml index 47c149e5129..d6743f70d5a 100644 --- a/src/compiler/args.ml +++ b/src/compiler/args.ml @@ -40,7 +40,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 = { @@ -158,7 +158,7 @@ let parse_args com = let all,max_length = Define.get_user_documentation_list com.user_defines in let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in List.iter (fun msg -> com.print (msg ^ "\n")) all; - exit 0 + raise Abort ) ),"","print help for all user defines"); ("Miscellaneous",["--help-metas"],[], Arg.Unit (fun() -> @@ -173,7 +173,7 @@ let parse_args com = let all,max_length = Meta.get_user_documentation_list com.user_metas in let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in List.iter (fun msg -> com.print (msg ^ "\n")) all; - exit 0 + raise Abort ) ),"","print help for all user metadatas"); ] in diff --git a/src/compiler/displayOutput.ml b/src/compiler/displayOutput.ml index 89951d65e17..46045ce6aad 100644 --- a/src/compiler/displayOutput.ml +++ b/src/compiler/displayOutput.ml @@ -71,8 +71,8 @@ let print_fields fields = | ITPackage(path,_) -> "package",snd path,"",None | ITModule path -> "type",snd path,"",None | ITMetadata meta -> - let s,(doc,_),_ = Meta.get_info meta in - "metadata","@" ^ s,"",doc_from_string doc + let s,data = Meta.get_info meta in + "metadata","@" ^ s,"",doc_from_string data.m_doc | ITTimer(name,value) -> "timer",name,"",doc_from_string value | ITLiteral s -> let t = match k.ci_type with None -> t_dynamic | Some (t,_) -> t in diff --git a/src/compiler/generate.ml b/src/compiler/generate.ml index 76e9f256dd5..0474ff95639 100644 --- a/src/compiler/generate.ml +++ b/src/compiler/generate.ml @@ -81,9 +81,10 @@ let generate ctx tctx ext actx = | Cs -> Gencs.generate,"cs" | Java -> - if Common.defined com Jvm then + if Common.defined com Jvm then begin + com.warning WDeprecated com.warning_options ("--java out.jar -D jvm is deprecated; use --jvm out.jar directly") null_pos; Genjvm.generate actx.jvm_flag,"java" - else + end else Genjava.generate,"java" | Python -> Genpy.generate,"python" diff --git a/src/context/common.ml b/src/context/common.ml index 7d1db468504..75394ee8e80 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -26,7 +26,6 @@ open Warning type package_rule = | Forbidden - | Directory of string | Remap of string type pos = Globals.pos diff --git a/src/context/display/displayFields.ml b/src/context/display/displayFields.ml index 7fc5eeeea1f..1c29954d810 100644 --- a/src/context/display/displayFields.ml +++ b/src/context/display/displayFields.ml @@ -99,12 +99,31 @@ let collect_static_extensions ctx items e p = | _ -> let items = loop items ctx.m.module_using in let items = loop items ctx.g.global_using in - let items = try - let mt = module_type_of_type e.etype in - loop items (t_infos mt).mt_using - with Exit -> - items + let rec loop_module_using items t = match follow_without_type t with + | TInst(c,_) -> + loop items c.cl_using + | TEnum(en,_) -> + loop items en.e_using + | TType(td,tl) -> + let items = loop items td.t_using in + loop_module_using items (apply_typedef td tl) + | TAbstract(a,_) -> + loop items a.a_using + | TAnon an -> + begin match !(an.a_status) with + | Statics c -> + loop items c.cl_using + | EnumStatics en -> + loop items en.e_using + | AbstractStatics a -> + loop items a.a_using + | _ -> + items + end + | _ -> + items in + let items = loop_module_using items e.etype in items let collect ctx e_ast e dk with_type p = diff --git a/src/context/display/displayJson.ml b/src/context/display/displayJson.ml index 8853ef2b225..8baf530a0b1 100644 --- a/src/context/display/displayJson.ml +++ b/src/context/display/displayJson.ml @@ -156,6 +156,71 @@ let handler = hctx.display#set_display_file (hctx.jsonrpc#get_bool_param "wasAutoTriggered") true; hctx.display#enable_display DMSignature ); + "display/metadata", (fun hctx -> + let include_compiler_meta = hctx.jsonrpc#get_bool_param "compiler" in + let include_user_meta = hctx.jsonrpc#get_bool_param "user" in + + hctx.com.callbacks#add_after_init_macros (fun () -> + let all = Meta.get_meta_list hctx.com.user_metas in + let all = List.filter (fun (_, (data:Meta.meta_infos)) -> + match data.m_origin with + | Compiler when include_compiler_meta -> true + | UserDefined _ when include_user_meta -> true + | _ -> false + ) all in + + hctx.send_result (jarray (List.map (fun (t, (data:Meta.meta_infos)) -> + let fields = [ + "name", jstring t; + "doc", jstring data.m_doc; + "parameters", jarray (List.map jstring data.m_params); + "platforms", jarray (List.map (fun p -> jstring (platform_name p)) data.m_platforms); + "targets", jarray (List.map (fun u -> jstring (Meta.print_meta_usage u)) data.m_used_on); + "internal", jbool data.m_internal; + "origin", jstring (match data.m_origin with + | Compiler -> "haxe compiler" + | UserDefined None -> "user-defined" + | UserDefined (Some o) -> o + ); + "links", jarray (List.map jstring data.m_links) + ] in + + (jobject fields) + ) all)) + ) + ); + "display/defines", (fun hctx -> + let include_compiler_defines = hctx.jsonrpc#get_bool_param "compiler" in + let include_user_defines = hctx.jsonrpc#get_bool_param "user" in + + hctx.com.callbacks#add_after_init_macros (fun () -> + let all = Define.get_define_list hctx.com.user_defines in + let all = List.filter (fun (_, (data:Define.define_infos)) -> + match data.d_origin with + | Compiler when include_compiler_defines -> true + | UserDefined _ when include_user_defines -> true + | _ -> false + ) all in + + hctx.send_result (jarray (List.map (fun (t, (data:Define.define_infos)) -> + let fields = [ + "name", jstring t; + "doc", jstring data.d_doc; + "parameters", jarray (List.map jstring data.d_params); + "platforms", jarray (List.map (fun p -> jstring (platform_name p)) data.d_platforms); + "origin", jstring (match data.d_origin with + | Compiler -> "haxe compiler" + | UserDefined None -> "user-defined" + | UserDefined (Some o) -> o + ); + "deprecated", jopt jstring data.d_deprecated; + "links", jarray (List.map jstring data.d_links) + ] in + + (jobject fields) + ) all)) + ) + ); "server/readClassPaths", (fun hctx -> hctx.com.callbacks#add_after_init_macros (fun () -> let cc = hctx.display#get_cs#get_context (Define.get_signature hctx.com.defines) in diff --git a/src/context/display/displayPath.ml b/src/context/display/displayPath.ml index 6ad580d420a..ebee57f7eb5 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 f1ab5eed318..541d769f70b 100644 --- a/src/context/display/displayToplevel.ml +++ b/src/context/display/displayToplevel.ml @@ -75,7 +75,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/context/typecore.ml b/src/context/typecore.ml index fc2b33ba64e..dc38a52648d 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -713,10 +713,13 @@ let get_next_stored_typed_expr_id = let uid = ref 0 in (fun() -> incr uid; !uid) +let make_stored_id_expr id p = + (EConst (Int (string_of_int id, None))), p + let store_typed_expr com te p = let id = get_next_stored_typed_expr_id() in com.stored_typed_exprs#add id te; - let eid = (EConst (Int (string_of_int id, None))), p in + let eid = make_stored_id_expr id p in id,((EMeta ((Meta.StoredTypedExpr,[],null_pos), eid)),p) let push_this ctx e = match e.eexpr with diff --git a/src/core/define.ml b/src/core/define.ml index d5d6bd6eb4d..bc135484bde 100644 --- a/src/core/define.ml +++ b/src/core/define.ml @@ -19,7 +19,35 @@ type define_origin = | Compiler | UserDefined of string option -let infos ?user_defines d = match (user_defines,d) with +type define_infos = { + d_doc : string; + d_params : string list; + d_platforms : Globals.platform list; + d_origin : define_origin; + d_links : string list; + d_deprecated : string option; +} + +let infos ?user_defines d = + let extract_infos (t, (doc, flags), origin) = + let params = ref [] and pfs = ref [] and links = ref [] and deprecated = ref None in + List.iter (function + | HasParam s -> params := s :: !params + | Platforms fl -> pfs := fl @ !pfs + | Link url -> links := url :: !links + | Deprecated s -> deprecated := Some s + ) flags; + (t, { + d_doc = doc; + d_params = !params; + d_platforms = !pfs; + d_origin = origin; + d_links = !links; + d_deprecated = !deprecated; + }) + in + + extract_infos (match (user_defines,d) with | (Some(user_defines), Custom(s)) when (Hashtbl.mem user_defines s) -> let infos = Hashtbl.find user_defines s in (s, (infos.doc, infos.flags), (UserDefined infos.source)) @@ -27,30 +55,23 @@ let infos ?user_defines d = match (user_defines,d) with (s, ("", []), Compiler) | _ -> let def,infos = DefineList.infos d in - (def, infos, Compiler) + (def, infos, Compiler)) let get_define_key d = - match (infos d) with (s,_,_) -> s + match (infos d) with (s,_) -> s let get_documentation user_defines d = - let t, (doc,flags), origin = infos ~user_defines:user_defines d in - let params = ref [] and pfs = ref [] in - List.iter (function - | HasParam s -> params := s :: !params - | Platforms fl -> pfs := fl @ !pfs - | Link _ -> () - | Deprecated _ -> () - ) flags; - let params = (match List.rev !params with + let t, data = infos ~user_defines:user_defines d in + let params = (match List.rev data.d_params with | [] -> "" | l -> "<" ^ String.concat ">, <" l ^ "> " ) in - let origin = match origin with + let origin = match data.d_origin with | UserDefined Some s -> " (from " ^ s ^ ")" | Compiler | UserDefined None -> "" in - let pfs = platform_list_help (List.rev !pfs) in - (String.concat "-" (ExtString.String.nsplit t "_")), params ^ doc ^ pfs ^ origin + let pfs = platform_list_help (List.rev data.d_platforms) in + (String.concat "-" (ExtString.String.nsplit t "_")), params ^ data.d_doc ^ pfs ^ origin let get_documentation_list user_defines = let m = ref 0 in @@ -77,6 +98,16 @@ let get_user_documentation_list user_defines = let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) user_defines_list in all,!m +let get_define_list user_defines = + let rec loop i acc = + let d = Obj.magic i in + if d <> Last then (infos ~user_defines d) :: loop (i + 1) acc + else acc + in + + let all = loop 0 (Hashtbl.fold (fun str _ acc -> (infos ~user_defines (Custom str)) :: acc) user_defines []) in + List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) all + let raw_defined ctx k = PMap.mem k ctx.values diff --git a/src/core/display/completionItem.ml b/src/core/display/completionItem.ml index bc2de80c829..16f47d54c01 100644 --- a/src/core/display/completionItem.ml +++ b/src/core/display/completionItem.ml @@ -761,42 +761,21 @@ let to_json ctx index item = ] | ITMetadata meta -> let open Meta in - let name,(doc,params),origin = Meta.get_info meta in + let name,data = Meta.get_info meta in let name = "@" ^ name in - let usage_to_string = function - | TClass -> "TClass" - | TClassField -> "TClassField" - | TAbstract -> "TAbstract" - | TAbstractField -> "TAbstractField" - | TEnum -> "TEnum" - | TTypedef -> "TTypedef" - | TAnyField -> "TAnyField" - | TExpr -> "TExpr" - | TTypeParameter -> "TTypeParameter" - | TVariable -> "TVariable" - in - let origin = match origin with - | Compiler -> Some "haxe compiler" - | UserDefined s -> s - in - let rec loop internal params platforms targets links l = match l with - | HasParam s :: l -> loop internal (s :: params) platforms targets links l - | Platforms pls :: l -> loop internal params ((List.map platform_name pls) @ platforms) targets links l - | UsedOn usages :: l -> loop internal params platforms ((List.map usage_to_string usages) @ targets) links l - | UsedInternally :: l -> loop true params platforms targets links l - | Link url :: l -> loop internal params platforms targets (url :: links) l - | [] -> internal,params,platforms,targets,links - in - let internal,params,platforms,targets,links = loop false [] [] [] [] params in "Metadata",jobject [ - "name",jstring name; - "doc",jstring doc; - "parameters",jlist jstring params; - "platforms",jlist jstring platforms; - "targets",jlist jstring targets; - "internal",jbool internal; - "links",jlist jstring links; - "origin",jopt jstring origin; + "name", jstring name; + "doc", jstring data.m_doc; + "parameters", jarray (List.map jstring data.m_params); + "platforms", jarray (List.map (fun p -> jstring (platform_name p)) data.m_platforms); + "targets", jarray (List.map (fun u -> jstring (Meta.print_meta_usage u)) data.m_used_on); + "internal", jbool data.m_internal; + "origin", jstring (match data.m_origin with + | Compiler -> "haxe compiler" + | UserDefined None -> "user-defined" + | UserDefined (Some o) -> o + ); + "links", jarray (List.map jstring data.m_links) ] | ITKeyword kwd ->"Keyword",jobject [ "name",jstring (s_keyword kwd) diff --git a/src/core/globals.ml b/src/core/globals.ml index 0b7750208bc..38ec7c33fd1 100644 --- a/src/core/globals.ml +++ b/src/core/globals.ml @@ -27,7 +27,7 @@ type platform = | Hl | Eval -let version = 4303 +let version = 4304 let version_major = version / 1000 let version_minor = (version mod 1000) / 100 let version_revision = (version mod 100) diff --git a/src/core/json/genjson.ml b/src/core/json/genjson.ml index ed85b04a7a1..9c04441e825 100644 --- a/src/core/json/genjson.ml +++ b/src/core/json/genjson.ml @@ -177,8 +177,8 @@ and generate_metadata_entry ctx (m,el,p) = and generate_metadata ctx ml = let ml = List.filter (fun (m,_,_) -> - let (_,(_,flags),_) = Meta.get_info m in - not (List.mem UsedInternally flags) + let (_,data) = Meta.get_info m in + not data.m_internal ) ml in jlist (generate_metadata_entry ctx) ml diff --git a/src/core/meta.ml b/src/core/meta.ml index 6dff5b0b0b2..fd1c9262b79 100644 --- a/src/core/meta.ml +++ b/src/core/meta.ml @@ -20,18 +20,49 @@ type meta_origin = | Compiler | UserDefined of string option +type meta_infos = { + m_internal : bool; + m_doc : string; + m_params : string list; + m_platforms : Globals.platform list; + m_used_on : meta_usage list; + m_origin : meta_origin; + m_links : string list; +} + let register_user_meta user_metas s data = Hashtbl.replace user_metas s data -let get_info ?user_metas m = match (user_metas,m) with +let get_info ?user_metas m = + let extract_infos (t, (doc, flags), origin) = + let params = ref [] and used = ref [] and pfs = ref [] and links = ref [] and internal = ref false in + List.iter (function + | HasParam s -> params := s :: !params + | Platforms fl -> pfs := fl @ !pfs + | UsedOn ul -> used := ul @ !used + | UsedInternally -> internal := true + | Link url -> links := url :: !links + ) flags; + (t,{ + m_internal = !internal; + m_doc = doc; + m_params = !params; + m_platforms = !pfs; + m_used_on = !used; + m_origin = origin; + m_links = !links; + }) + in + + extract_infos (match (user_metas,m) with | (Some(user_metas), Custom(s)) when (Hashtbl.mem user_metas s) -> let infos = Hashtbl.find user_metas s in (s, (infos.doc, infos.flags), (UserDefined infos.source)) | _ -> let meta,infos = MetaList.get_info m in - (meta, infos, Compiler) + (meta, infos, Compiler)) -let to_string m = match (get_info m) with (s,_,_) -> s +let to_string m = match (get_info m) with (s,_) -> s let hmeta = let h = Hashtbl.create 0 in @@ -53,30 +84,19 @@ let from_string s = | '$' -> Dollar (String.sub s 1 (String.length s - 1)) | _ -> Custom s -let get_documentation user_metas d = - let t, (doc,flags), origin = get_info ~user_metas:user_metas d in - if not (List.mem UsedInternally flags) then begin - let params = ref [] and used = ref [] and pfs = ref [] in - List.iter (function - | HasParam s -> params := s :: !params - | Platforms fl -> pfs := fl @ !pfs - | UsedOn ul -> used := ul @ !used - | UsedInternally -> die "" __LOC__ - | Link _ -> () - ) flags; - let params = (match List.rev !params with +let get_documentation user_metas m = + let t, data = get_info ~user_metas:user_metas m in + if data.m_internal then None else + let params = (match List.rev data.m_params with | [] -> "" | l -> "(<" ^ String.concat ">, <" l ^ ">) " ) in - let pfs = platform_list_help (List.rev !pfs) in - let origin = match origin with + let pfs = platform_list_help (List.rev data.m_platforms) in + let origin = match data.m_origin with | UserDefined Some s -> " (from " ^ s ^ ")" | Compiler | UserDefined None -> "" in - let str = "@" ^ t in - Some (str,params ^ doc ^ pfs ^ origin) - end else - None + Some ("@" ^ t, params ^ data.m_doc ^ pfs ^ origin) let get_documentation_list user_metas = let m = ref 0 in @@ -93,6 +113,16 @@ let get_documentation_list user_metas = let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in all,!m +let get_meta_list user_metas = + let rec loop i acc = + let d = Obj.magic i in + if d <> Last then (get_info ~user_metas d) :: loop (i + 1) acc + else acc + in + + let all = loop 0 (Hashtbl.fold (fun str _ acc -> (get_info ~user_metas (Custom str)) :: acc) user_metas []) in + List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) all + let get_all user_metas = let rec loop i acc = let d = Obj.magic i in @@ -108,7 +138,7 @@ let get_user_documentation_list user_metas = let user_meta_list = (Hashtbl.fold (fun meta _ acc -> begin match get_documentation user_metas (Custom meta) with | None -> acc - | Some (str, desc) -> + | Some (str,desc) -> if String.length str > !m then m := String.length str; (str,desc) :: acc end diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml index 2879e5ff212..8386f9ac776 100644 --- a/src/core/tFunctions.ml +++ b/src/core/tFunctions.ml @@ -663,6 +663,13 @@ let rec module_type_of_type = function (match r.tm_type with | Some t -> module_type_of_type t | _ -> raise Exit) + | TAnon an -> + begin match !(an.a_status) with + | Statics c -> TClassDecl c + | EnumStatics en -> TEnumDecl en + | AbstractStatics a -> TAbstractDecl a + | _ -> raise Exit + end | _ -> raise Exit diff --git a/src/filters/exceptions.ml b/src/filters/exceptions.ml index 609e108f3a7..d95b8076bd5 100644 --- a/src/filters/exceptions.ml +++ b/src/filters/exceptions.ml @@ -204,7 +204,7 @@ let throw_native ctx e_thrown t p = else e_thrown in - mk (TThrow e_native) t p + e_native let set_needs_exception_stack v = if not (Meta.has Meta.NeedsExceptionStack v.v_meta) then diff --git a/src/generators/genjvm.ml b/src/generators/genjvm.ml index 59958186c26..02db415c2f8 100644 --- a/src/generators/genjvm.ml +++ b/src/generators/genjvm.ml @@ -2086,7 +2086,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/generators/hl2c.ml b/src/generators/hl2c.ml index 871005304b2..daf452e4027 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/src/generators/hlopt.ml b/src/generators/hlopt.ml index 2e5bd20c4c6..d60e88b47c0 100644 --- a/src/generators/hlopt.ml +++ b/src/generators/hlopt.ml @@ -47,6 +47,7 @@ type block = { mutable bneed : ISet.t; mutable bneed_all : ISet.t option; mutable bwrite : (int, int) PMap.t; + mutable btrap : int list; } type control = @@ -54,6 +55,7 @@ type control = | CJCond of int | CJAlways of int | CTry of int + | CCatch | CSwitch of int array | CRet | CThrow @@ -75,6 +77,8 @@ let control = function CSwitch cases | OTrap (_,d) -> CTry d + | OEndTrap _ -> + CCatch | _ -> CNo @@ -444,7 +448,7 @@ let code_graph (f:fundecl) = | CJAlways d | CJCond d -> Hashtbl.replace all_blocks (i + 1 + d) true | _ -> () done; - let rec make_block pos = + let rec make_block trapl pos = try Hashtbl.find blocks_pos pos with Not_found -> @@ -458,11 +462,12 @@ let code_graph (f:fundecl) = bneed = ISet.empty; bwrite = PMap.empty; bneed_all = None; + btrap = trapl; } in Hashtbl.add blocks_pos pos b; let rec loop i = - let goto d = - let b2 = make_block (i + 1 + d) in + let goto ?(tl=b.btrap) d = + let b2 = make_block tl (i + 1 + d) in b2.bprev <- b :: b2.bprev; b2 in @@ -472,7 +477,8 @@ let code_graph (f:fundecl) = end else match control (op i) with | CNo -> loop (i + 1) - | CRet | CThrow -> + | CRet -> + assert(b.btrap = []); b.bend <- i | CJAlways d -> b.bend <- i; @@ -480,9 +486,27 @@ let code_graph (f:fundecl) = | CSwitch pl -> b.bend <- i; b.bnext <- goto 0 :: Array.to_list (Array.map goto pl) - | CJCond d | CTry d -> + | CJCond d -> b.bend <- i; b.bnext <- [goto 0; goto d]; + | CTry d -> + b.bend <- i; + b.bnext <- [goto ~tl:((i+1+d)::b.btrap) 0; goto d]; + | CThrow -> + b.bend <- i; + match b.btrap with + | [] -> () + | [p] -> b.bnext <- [goto ~tl:[] (p-1-i)]; + | p :: pl -> b.bnext <- [goto ~tl:pl (p-1-i)]; + ; + | CCatch -> + let p, pl = match b.btrap with + | [] -> assert false; + | [p] -> p, [] + | p :: pl -> p, pl + in + b.bend <- i; + b.bnext <- [goto ~tl:pl 0; goto ~tl:pl (p-1-i)]; | CLabel -> b.bloop <- true; loop (i + 1) @@ -490,7 +514,7 @@ let code_graph (f:fundecl) = loop pos; b in - blocks_pos, make_block 0 + blocks_pos, make_block [] 0 type rctx = { r_root : block; diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index c44b80491b2..6011ae7be39 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -492,7 +492,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/optimization/analyzer.ml b/src/optimization/analyzer.ml index 8b79d8d6e42..82ab684ed66 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/src/optimization/analyzerTexpr.ml b/src/optimization/analyzerTexpr.ml index 153797217e9..39dcac8b4ae 100644 --- a/src/optimization/analyzerTexpr.ml +++ b/src/optimization/analyzerTexpr.ml @@ -538,7 +538,7 @@ module Fusion = struct (* no-side-effect *) | {eexpr = TFunction _ | TConst _ | TTypeExpr _} :: el -> block_element acc el - | {eexpr = TMeta((Meta.Pure,_,_),_)} :: el -> + | {eexpr = TMeta((Meta.Pure,_,_) as meta,_)} :: el when PurityState.get_purity_from_meta [meta] = Pure -> block_element acc el | {eexpr = TCall({eexpr = TField(e1,fa)},el1)} :: el2 when PurityState.is_pure_field_access fa && config.local_dce -> block_element acc (e1 :: el1 @ el2) diff --git a/src/optimization/analyzerTexprTransformer.ml b/src/optimization/analyzerTexprTransformer.ml index 8a519d0da3e..640920516ad 100644 --- a/src/optimization/analyzerTexprTransformer.ml +++ b/src/optimization/analyzerTexprTransformer.ml @@ -118,11 +118,15 @@ let rec func ctx bb tf t p = let bb,e2 = value bb e2 in bb,{e with eexpr = TBinop(op,e1,e2)} | TBinop(op,e1,e2) -> - let bb,e1,e2 = match ordered_value_list bb [e1;e2] with - | bb,[e1;e2] -> bb,e1,e2 - | _ -> die "" __LOC__ - in - bb,{e with eexpr = TBinop(op,e1,e2)} + begin match ordered_value_list bb [e1;e2] with + | bb,[e1;e2] -> + bb,{e with eexpr = TBinop(op,e1,e2)} + | bb,[e] -> + assert(bb == g.g_unreachable); + bb,e + | _ -> + die "" __LOC__ + end | TUnop(op,flag,e1) -> let bb,e1 = value bb e1 in bb,{e with eexpr = TUnop(op,flag,e1)} @@ -139,11 +143,16 @@ let rec func ctx bb tf t p = let bb,e1 = value bb e1 in bb,{e with eexpr = TField(e1,fa)} | TArray(e1,e2) -> - let bb,e1,e2 = match ordered_value_list bb [e1;e2] with - | bb,[e1;e2] -> bb,e1,e2 - | _ -> die "" __LOC__ - in - bb,{e with eexpr = TArray(e1,e2)} + begin match ordered_value_list bb [e1;e2] with + | bb,[e1;e2] -> + bb,{e with eexpr = TArray(e1,e2)} + + | bb,[e] -> + assert(bb == g.g_unreachable); + bb,e + | _ -> + die "" __LOC__ + end | TMeta(m,e1) -> let bb,e1 = value bb e1 in bb,{e with eexpr = TMeta(m,e1)} diff --git a/src/optimization/dce.ml b/src/optimization/dce.ml index 09e547b5c28..4e7b1fc98a1 100644 --- a/src/optimization/dce.ml +++ b/src/optimization/dce.ml @@ -492,6 +492,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; @@ -586,10 +595,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; @@ -610,10 +624,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 @@ -636,12 +652,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/src/syntax/grammar.mly b/src/syntax/grammar.mly index 186451299de..addcf848dde 100644 --- a/src/syntax/grammar.mly +++ b/src/syntax/grammar.mly @@ -1135,8 +1135,6 @@ and block_with_pos' acc f p s = | Stream.Error msg when !in_display_file -> handle_stream_error msg s; (block_with_pos acc (next_pos s) s) - | Error (e,p) when !in_display_file -> - block_with_pos acc p s and block_with_pos acc p s = block_with_pos' acc parse_block_elt p s diff --git a/src/typing/calls.ml b/src/typing/calls.ml index eb9eeb3cf45..234d3aca393 100644 --- a/src/typing/calls.ml +++ b/src/typing/calls.ml @@ -218,8 +218,8 @@ let rec acc_get ctx g = | AKUsingAccessor sea | AKUsingField sea when ctx.in_display -> (* Generate a TField node so we can easily match it for position/usage completion (issue #1968) *) let e_field = FieldAccess.get_field_expr sea.se_access FGet in - (* TODO *) - (* let ec = {ec with eexpr = (TMeta((Meta.StaticExtension,[],null_pos),ec))} in *) + let id,_ = store_typed_expr ctx.com sea.se_this e_field.epos in + let e_field = {e_field with eexpr = (TMeta((Meta.StaticExtension,[make_stored_id_expr id e_field.epos],null_pos),e_field))} in let t = match follow e_field.etype with | TFun (_ :: args,ret) -> TFun(args,ret) | t -> t @@ -377,7 +377,7 @@ let type_bind ctx (e : texpr) (args,ret) params p = let rec loop args params given_args missing_args ordered_args = match args, params with | [], [] -> given_args,missing_args,ordered_args | [], _ -> typing_error "Too many callback arguments" p - | (n,o,t) :: args , [] when o -> + | (n,o,t) :: args , [] when not (Define.defined ctx.com.defines Define.HaxeNext) && o -> let a = if is_pos_infos t then let infos = mk_infos ctx p [] in ordered_args @ [type_expr ctx infos (WithType.with_argument t n)] @@ -387,6 +387,10 @@ let type_bind ctx (e : texpr) (args,ret) params p = ordered_args in loop args [] given_args missing_args a + | [n,o,t] , [] when o && is_pos_infos t -> + let infos = mk_infos ctx p [] in + let ordered_args = ordered_args @ [type_expr ctx infos (WithType.with_argument t n)] in + given_args,missing_args,ordered_args | (n,o,t) :: _ , (EConst(Ident "_"),p) :: _ when not ctx.com.config.pf_can_skip_non_nullable_argument && o && not (is_nullable t) -> typing_error "Usage of _ is not supported for optional non-nullable arguments" p | (n,o,t) :: args , ([] as params) diff --git a/src/typing/fields.ml b/src/typing/fields.ml index 77ad56eb5e4..0147b0b6ac0 100644 --- a/src/typing/fields.ml +++ b/src/typing/fields.ml @@ -272,7 +272,13 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) = | None -> raise Not_found in let type_field_by_et f e t = - f { e with etype = t } (follow_without_type t) + let e = match ctx.com.platform with + | Cs -> + {e with etype = t} + | _ -> + mk (TCast(e,None)) t e.epos + in + f e (follow_without_type t) in let type_field_by_e f e = f e (follow_without_type e.etype) diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index 64844182211..10b8cf8fe03 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -883,9 +883,5 @@ let interpret ctx = let setup() = Interp.setup Interp.macro_api -let type_stored_expr ctx e1 = - let id = match e1 with (EConst (Int (s, _)),_) -> int_of_string s | _ -> die "" __LOC__ in - TyperBase.get_stored_typed_expr ctx id - ;; load_macro_ref := load_macro; diff --git a/src/typing/matcher.ml b/src/typing/matcher.ml index 6ca7e9a3535..450b619e1ba 100644 --- a/src/typing/matcher.ml +++ b/src/typing/matcher.ml @@ -367,7 +367,11 @@ module Pattern = struct | 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 @@ -548,7 +552,7 @@ module Pattern = struct ignore(TyperDisplay.handle_edisplay ctx e (display_mode()) MGet (WithType.with_type t)); pat | EMeta((Meta.StoredTypedExpr,_,_),e1) -> - let e1 = MacroContext.type_stored_expr ctx e1 in + let e1 = TyperBase.type_stored_expr ctx e1 in loop (TExprToExpr.convert_expr e1) | _ -> fail() diff --git a/src/typing/operators.ml b/src/typing/operators.ml index 90740b56d33..ed932108e6c 100644 --- a/src/typing/operators.ml +++ b/src/typing/operators.ml @@ -237,14 +237,22 @@ let make_binop ctx op e1 e2 is_assign_op with_type p = if unify_int ctx e1 KUnk then tint else tfloat | KUnk , KFloat | KUnk , KString -> - unify ctx e1.etype e2.etype e1.epos; - e1.etype + if Define.defined ctx.com.defines Define.HaxeNext then + e2.etype + else begin + unify ctx e1.etype e2.etype e1.epos; + e1.etype + end | KInt , KUnk -> if unify_int ctx e2 KUnk then tint else tfloat | KFloat , KUnk | KString , KUnk -> - unify ctx e2.etype e1.etype e2.epos; - e2.etype + if Define.defined ctx.com.defines Define.HaxeNext then + e1.etype + else begin + unify ctx e2.etype e1.etype e2.epos; + e2.etype + end | _ , KString | KString , _ -> tstring diff --git a/src/typing/typeloadCheck.ml b/src/typing/typeloadCheck.ml index 6e649860f86..f39e80b6098 100644 --- a/src/typing/typeloadCheck.ml +++ b/src/typing/typeloadCheck.ml @@ -510,7 +510,7 @@ module Inheritance = struct match m with | Meta.AutoBuild, el, p -> c.cl_meta <- (Meta.Build,el,{ c.cl_pos with pmax = c.cl_pos.pmin }(* prevent display metadata *)) :: m :: c.cl_meta | _ -> () - ) csup.cl_meta; + ) (if (Define.defined ctx.com.defines Define.HaxeNext) then (List.rev csup.cl_meta) else csup.cl_meta); if has_class_flag csup CFinal && not (((has_class_flag csup CExtern) && Meta.has Meta.Hack c.cl_meta) || (match c.cl_kind with KTypeParameter _ -> true | _ -> false)) then typing_error ("Cannot extend a final " ^ if (has_class_flag c CInterface) then "interface" else "class") p; in diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index dd47ae44a9f..175608066b3 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -663,6 +663,7 @@ let create_typer_context_for_field ctx cctx fctx cff = monomorphs = { perfunction = []; }; + type_params = if fctx.is_static && not fctx.is_abstract_member && not (Meta.has Meta.LibType cctx.tclass.cl_meta) (* TODO: remove this *) then [] else ctx.type_params; } in let c = cctx.tclass in if (fctx.is_abstract && not (has_meta Meta.LibType c.cl_meta)) then begin diff --git a/src/typing/typeloadParse.ml b/src/typing/typeloadParse.ml index 066443ada4e..17379ef0b77 100644 --- a/src/typing/typeloadParse.ml +++ b/src/typing/typeloadParse.ml @@ -83,25 +83,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 *) diff --git a/src/typing/typer.ml b/src/typing/typer.ml index 70263b008a6..5047c26bc31 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -1677,7 +1677,7 @@ and type_meta ?(mode=MGet) ctx m e1 with_type p = | _ -> e() end | (Meta.StoredTypedExpr,_,_) -> - MacroContext.type_stored_expr ctx e1 + type_stored_expr ctx e1 | (Meta.NoPrivateAccess,_,_) -> ctx.meta <- List.filter (fun(m,_,_) -> m <> Meta.PrivateAccess) ctx.meta; e() diff --git a/src/typing/typerBase.ml b/src/typing/typerBase.ml index 656d2d660c6..ca6192d7ac8 100644 --- a/src/typing/typerBase.ml +++ b/src/typing/typerBase.ml @@ -177,6 +177,10 @@ let get_stored_typed_expr ctx id = let e = ctx.com.stored_typed_exprs#find id in Texpr.duplicate_tvars (fun e -> get_this ctx e.epos) e +let type_stored_expr ctx e1 = + let id = match e1 with (EConst (Int (s, _)),_) -> int_of_string s | _ -> die "" __LOC__ in + get_stored_typed_expr ctx id + let assign_to_this_is_allowed ctx = match ctx.curclass.cl_kind with | KAbstractImpl _ -> diff --git a/src/typing/typerDisplay.ml b/src/typing/typerDisplay.ml index 20fa84fdfaf..9bb7ce90b12 100644 --- a/src/typing/typerDisplay.ml +++ b/src/typing/typerDisplay.ml @@ -346,20 +346,40 @@ and display_expr ctx e_ast e dk mode with_type p = let fa = get_constructor_access c params p in fa.fa_field,c in - let maybe_expand_overload e e_on host cf = match mode with + let maybe_expand_overload el_typed e e_on host cf = match mode with | MCall el when cf.cf_overloads <> [] -> let fa = FieldAccess.create e_on cf host false p in - let fcc = unify_field_call ctx fa [] el p false in + let fcc = unify_field_call ctx fa el_typed el p false in FieldAccess.get_field_expr {fa with fa_field = fcc.fc_field} FCall | _ -> e in + let e,el_typed = match fst e_ast,e.eexpr with + | _,TMeta((Meta.StaticExtension,[e_self],_),e1) -> + e1,[type_stored_expr ctx e_self] + | EField((_,_,EFSafe)),e1 -> + (* For ?. we want to extract the then-expression of the TIf. *) + let rec loop e1 = match e1.eexpr with + | TIf({eexpr = TBinop(OpNotEq,_,{eexpr = TConst TNull})},e1,Some _) -> + e1 + | TBlock el -> + begin match List.rev el with + | e :: _ -> loop e + | _ -> e + end + | _ -> + e + in + loop e,[] + | _ -> + e,[] + in (* If we display on a TField node that points to an overloaded field, let's try to unify the field call in order to resolve the correct overload (issue #7753). *) let e = match e.eexpr with - | TField(e1,FStatic(c,cf)) -> maybe_expand_overload e e1 (FHStatic c) cf - | TField(e1,(FInstance(c,tl,cf) | FClosure(Some(c,tl),cf))) -> maybe_expand_overload e e1 (FHInstance(c,tl)) cf - | TField(e1,(FAnon cf | FClosure(None,cf))) -> maybe_expand_overload e e1 FHAnon cf + | TField(e1,FStatic(c,cf)) -> maybe_expand_overload el_typed e e1 (FHStatic c) cf + | TField(e1,(FInstance(c,tl,cf) | FClosure(Some(c,tl),cf))) -> maybe_expand_overload el_typed e e1 (FHInstance(c,tl)) cf + | TField(e1,(FAnon cf | FClosure(None,cf))) -> maybe_expand_overload el_typed e e1 FHAnon cf | _ -> e in match ctx.com.display.dms_kind with @@ -405,6 +425,8 @@ and display_expr ctx e_ast e dk mode with_type p = end | TCall(e1,_) -> loop e1 + | TCast(e1,_) -> + loop e1 | _ -> () in @@ -460,6 +482,8 @@ and display_expr ctx e_ast e dk mode with_type p = end | TCall(e1,_) -> loop e1 + | TCast(e1,_) -> + loop e1 | _ -> [] in diff --git a/tests/display/src/Diagnostic.hx b/std/haxe/display/Diagnostic.hx similarity index 98% rename from tests/display/src/Diagnostic.hx rename to std/haxe/display/Diagnostic.hx index 697e70392a0..f805a1e5121 100644 --- a/tests/display/src/Diagnostic.hx +++ b/std/haxe/display/Diagnostic.hx @@ -1,4 +1,6 @@ // from vshaxe +package haxe.display; + import haxe.display.Position.Location; import haxe.display.Position.Range; import haxe.display.JsonModuleTypes; diff --git a/std/haxe/display/Display.hx b/std/haxe/display/Display.hx index 1fb1b19183b..aac5724c846 100644 --- a/std/haxe/display/Display.hx +++ b/std/haxe/display/Display.hx @@ -78,6 +78,16 @@ class DisplayMethods { **/ static inline var SignatureHelp = new HaxeRequestMethod("display/signatureHelp"); + /** + The metadata request is sent from the client to Haxe to get a list of all registered metadata and their documentation. + **/ + static inline var Metadata = new HaxeRequestMethod("display/metadata"); + + /** + The defines request is sent from the client to Haxe to get a list of all registered defines and their documentation. + **/ + static inline var Defines = new HaxeRequestMethod("display/defines"); + /* TODO: @@ -306,6 +316,8 @@ typedef Define = { var parameters:Array; var platforms:Array; var links:Array; + var ?origin:String; + var ?deprecated:String; } typedef Keyword = { @@ -543,6 +555,20 @@ typedef SignatureItem = { typedef SignatureHelpResult = Response>; +typedef MetadataParams = { + var compiler:Bool; + var user:Bool; +} + +typedef MetadataResult = Response>; + +typedef DefinesParams = { + var compiler:Bool; + var user:Bool; +} + +typedef DefinesResult = Response>; + /** General types **/ typedef PositionParams = FileParams & { /** Unicode character offset in the file. **/ diff --git a/std/haxe/format/JsonPrinter.hx b/std/haxe/format/JsonPrinter.hx index c6ab3ee514d..20cd597cd93 100644 --- a/std/haxe/format/JsonPrinter.hx +++ b/std/haxe/format/JsonPrinter.hx @@ -165,16 +165,15 @@ class JsonPrinter { function fieldsString(v:Dynamic, fields:Array) { addChar('{'.code); var len = fields.length; - var last = len - 1; - var first = true; + var empty = true; for (i in 0...len) { var f = fields[i]; var value = Reflect.field(v, f); if (Reflect.isFunction(value)) continue; - if (first) { + if (empty) { nind++; - first = false; + empty = false; } else addChar(','.code); newl(); @@ -184,11 +183,11 @@ class JsonPrinter { if (pretty) addChar(' '.code); write(f, value); - if (i == last) { - nind--; - newl(); - ipad(); - } + } + if (!empty) { + nind--; + newl(); + ipad(); } addChar('}'.code); } diff --git a/std/haxe/macro/Compiler.hx b/std/haxe/macro/Compiler.hx index 0ef487a7ced..e825937054a 100644 --- a/std/haxe/macro/Compiler.hx +++ b/std/haxe/macro/Compiler.hx @@ -76,8 +76,10 @@ class Compiler { } #if (!neko && !eval) + @:deprecated("Will be removed in Haxe 5.0") private static function typePatch(cl:String, f:String, stat:Bool, t:String) {} + @:deprecated("Will be removed in Haxe 5.0") private static function metaPatch(meta:String, cl:String, f:String, stat:Bool) {} private static function addGlobalMetadataImpl(pathFilter:String, meta:String, recursive:Bool, toTypes:Bool, toFields:Bool) {} @@ -87,6 +89,7 @@ class Compiler { Removes a (static) field from a given class by name. An error is thrown when `className` or `field` is invalid. **/ + @:deprecated("Will be removed in Haxe 5.0") public static function removeField(className:String, field:String, ?isStatic:Bool) { if (!path.match(className)) throw "Invalid " + className; @@ -107,6 +110,7 @@ class Compiler { Set the type of a (static) field at a given class by name. An error is thrown when `className` or `field` is invalid. **/ + @:deprecated("Will be removed in Haxe 5.0") public static function setFieldType(className:String, field:String, type:String, ?isStatic:Bool) { if (!path.match(className)) throw "Invalid " + className; @@ -127,6 +131,7 @@ class Compiler { Add metadata to a (static) field or class by name. An error is thrown when `className` or `field` is invalid. **/ + @:deprecated public static function addMetadata(meta:String, className:String, ?field:String, ?isStatic:Bool) { if (!path.match(className)) throw "Invalid " + className; @@ -373,6 +378,7 @@ class Compiler { /** Load a type patch file that can modify the field types within declared classes and enums. **/ + @:deprecated("Will be removed in Haxe 5.0") public static function patchTypes(file:String):Void { var file = Context.resolvePath(file); var f = sys.io.File.read(file, true); diff --git a/std/neko/Boot.hx b/std/neko/Boot.hx index 19ff40aa0b4..cd2b1decdbb 100644 --- a/std/neko/Boot.hx +++ b/std/neko/Boot.hx @@ -48,7 +48,11 @@ class Boot { i += 1; } e.__string = old; + #if haxe_next + return NativeString.ofString(s + untyped ")".__s); + #else return s + untyped ")".__s; + #end } private static function __interfLoop(cc:Dynamic, cl:Dynamic) { diff --git a/tests/RunCi.hx b/tests/RunCi.hx index 309b514be32..8ccf0a9525e 100644 --- a/tests/RunCi.hx +++ b/tests/RunCi.hx @@ -46,7 +46,7 @@ class RunCi { infoMsg('test $test'); try { changeDirectory(unitDir); - haxelibInstallGit("haxe-utest", "utest", "master", "--always"); + haxelibInstallGit("haxe-utest", "utest", "a94f8812e8786f2b5fec52ce9f26927591d26327", "--always"); var args = switch (ci) { case null: diff --git a/tests/display/build.hxml b/tests/display/build.hxml index b751ec6b939..97dea9fdd1a 100644 --- a/tests/display/build.hxml +++ b/tests/display/build.hxml @@ -5,4 +5,4 @@ -lib haxeserver --interp -D use-rtti-doc -#-D test=9133 \ No newline at end of file +-D test=11285 \ No newline at end of file diff --git a/tests/display/src/cases/Issue10106.hx b/tests/display/src/cases/Issue10106.hx new file mode 100644 index 00000000000..165c9170f45 --- /dev/null +++ b/tests/display/src/cases/Issue10106.hx @@ -0,0 +1,57 @@ +package cases; + +class Issue10106 extends DisplayTestCase { + /** + class CExtension { + public static function toS(c: C): String { + return 'c'; + } + public static function fromS(cls: Class, s: String):C { + return new C(); + } + } + + @:using(cases.Issue10106.CExtension) + class C { + public function new(){} + } + + + class Main { + static public function main() { + C.{-1-} + } + } + **/ + function testClass() { + eq(true, hasField(fields(pos(1)), "fromS", "(s : String) -> cases.C")); + } + + /** + class EnExtension { + public static function toS(e:En):String { + return '${e}'; + } + + public static function fromS(en:Enum, s:String):En { + return A; + } + } + + @:using(cases.Issue10106.EnExtension) + enum En { + A; + B; + } + + + class Main { + static public function main() { + En.{-1-} + } + } + **/ + function testEnum() { + eq(true, hasField(fields(pos(1)), "fromS", "(s : String) -> cases.En")); + } +} diff --git a/tests/display/src/cases/Issue11205.hx b/tests/display/src/cases/Issue11205.hx new file mode 100644 index 00000000000..2cc85c99970 --- /dev/null +++ b/tests/display/src/cases/Issue11205.hx @@ -0,0 +1,22 @@ +package cases; + +class Issue11205 extends DisplayTestCase { + /** + typedef Foo = { + var {-1-}bar{-2-}:{ + var {-3-}value{-4-}:Int; + }; + } + function main() { + final foo:Foo = cast null; + foo?.b{-5-}ar?.v{-6-}alue; + } + **/ + function test() { + eq(range(1, 2), position(pos(5))); + eq("{ value : Int }", type(pos(5))); + + eq(range(3, 4), position(pos(6))); + eq("Null", type(pos(6))); + } +} diff --git a/tests/display/src/cases/Issue11285.hx b/tests/display/src/cases/Issue11285.hx new file mode 100644 index 00000000000..b0735473e7c --- /dev/null +++ b/tests/display/src/cases/Issue11285.hx @@ -0,0 +1,34 @@ +package cases; + +class Issue11285 extends DisplayTestCase { + /** + using Issue11285.MathTools; + + function main() { + var float = 0.0; + var int = 0; + float.wrapA{-1-}round(0, 1); + int.wrap{-2-}Around(0, 1); + } + + class MathTools { + + extern overload public static inline function {-3-}wrapAround{-4-}(v:Int, min:Int, max:Int):Int { + var range = max - min; + return min + (((v - min) % range) + range) % range; + } + + extern overload public static inline function {-5-}wrapAround{-6-}(v:Float, min:Float, max:Float):Float { + var range = max - min; + return min + (((v - min) % range) + range) % range; + } + } + **/ + function test() { + eq(range(5, 6), position(pos(1))); + eq("(v : Float, min : Float, max : Float) -> Float", type(pos(1))); + + eq(range(3, 4), position(pos(2))); + eq("(v : Int, min : Int, max : Int) -> Int", type(pos(2))); + } +} diff --git a/tests/display/src/import.hx b/tests/display/src/import.hx index 6702d1e03be..d8407128893 100644 --- a/tests/display/src/import.hx +++ b/tests/display/src/import.hx @@ -1 +1 @@ -import Diagnostic; +import haxe.display.Diagnostic; diff --git a/tests/misc/hl/reserved-keywords/Macro.macro.hx b/tests/misc/hl/reserved-keywords/Macro.macro.hx index a47548b6cea..9e76e54d2eb 100644 --- a/tests/misc/hl/reserved-keywords/Macro.macro.hx +++ b/tests/misc/hl/reserved-keywords/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; } } diff --git a/tests/misc/projects/Issue10844/user-defined-meta-json-pretty-fail.hxml b/tests/misc/projects/Issue10844/user-defined-meta-json-pretty-fail.hxml deleted file mode 100644 index 68353040073..00000000000 --- a/tests/misc/projects/Issue10844/user-defined-meta-json-pretty-fail.hxml +++ /dev/null @@ -1,4 +0,0 @@ -user-defined-meta-json-fail.hxml --D message.reporting=pretty --D message.no-color - diff --git a/tests/misc/projects/Issue10844/user-defined-meta-json-pretty-fail.hxml.stderr b/tests/misc/projects/Issue10844/user-defined-meta-json-pretty-fail.hxml.stderr deleted file mode 100644 index 58944a79f12..00000000000 --- a/tests/misc/projects/Issue10844/user-defined-meta-json-pretty-fail.hxml.stderr +++ /dev/null @@ -1,12 +0,0 @@ -[ERROR] --macro haxe.macro.Compiler.registerMetadataDescriptionFile('meta.jsno', 'myapp') - - | Uncaught exception Could not read file meta.jsno - - -> $$normPath(::std::)/haxe/macro/Compiler.hx:491: characters 11-39 - - 491 | var f = sys.io.File.getContent(path); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | Called from here - - | Called from here - diff --git a/tests/misc/projects/Issue11582/Macro.macro.hx b/tests/misc/projects/Issue11582/Macro.macro.hx new file mode 100644 index 00000000000..55f1d185b26 --- /dev/null +++ b/tests/misc/projects/Issue11582/Macro.macro.hx @@ -0,0 +1,27 @@ +class Macro { + static var id = 0; + static function build(i:String) { + if (haxe.macro.Context.getLocalClass().get().isInterface) return null; + + var hasMacros = false; + var fields = haxe.macro.Context.getBuildFields(); + for (f in fields) { + if (f.name == "macros") { + hasMacros = true; + break; + } + } + + if (!hasMacros) + fields = (macro class A { + public static var macros = []; + }).fields.concat(fields); + + var id = '_' + id++; + fields.push((macro class A { + static var $id = {macros.push($v{i}); 0;}; + }).fields[0]); + + return fields; + } +} diff --git a/tests/misc/projects/Issue11582/Main.hx b/tests/misc/projects/Issue11582/Main.hx new file mode 100644 index 00000000000..26f3b118d02 --- /dev/null +++ b/tests/misc/projects/Issue11582/Main.hx @@ -0,0 +1,51 @@ +class Main { + static function main() { + trace("Foo"); + trace(Foo1.macros); + trace(Foo2.macros); + trace(Foo3.macros); + trace(Foo4.macros); + + trace("Bar"); + trace(Bar1.macros); + trace(Bar2.macros); + trace(Bar3.macros); + + trace("Baz"); + trace(Baz1.macros); + trace(Baz2.macros); + trace(Baz3.macros); + } +} + +@:autoBuild(Macro.build("I1")) +interface I1 {} + +@:autoBuild(Macro.build("I2")) +interface I2 {} + +@:autoBuild(Macro.build("auto Foo1 (1)")) +@:autoBuild(Macro.build("auto Foo1 (2)")) +@:build(Macro.build("Foo1")) +class Foo1 implements I1 implements I2 {} + +@:build(Macro.build("Foo2")) +class Foo2 extends Foo1 {} + +@:build(Macro.build("Foo3 (1)")) +@:build(Macro.build("Foo3 (2)")) +class Foo3 extends Foo2 {} + +@:build(Macro.build("Foo4")) +class Foo4 extends Foo3 {} + +class Bar1 implements I2 implements I1 {} +class Bar2 extends Bar1 {} +class Bar3 extends Bar2 {} + +@:autoBuild(Macro.build("I3")) +interface I3 extends I1 {} + +class Baz1 implements I3 implements I2 {} +class Baz2 extends Baz1 {} +class Baz3 extends Baz2 {} diff --git a/tests/misc/projects/Issue11582/compile.hxml b/tests/misc/projects/Issue11582/compile.hxml new file mode 100644 index 00000000000..4eae8a74dc8 --- /dev/null +++ b/tests/misc/projects/Issue11582/compile.hxml @@ -0,0 +1,3 @@ +-main Main +-D haxe-next +--interp diff --git a/tests/misc/projects/Issue11582/compile.hxml.stdout b/tests/misc/projects/Issue11582/compile.hxml.stdout new file mode 100644 index 00000000000..d85a3c1e974 --- /dev/null +++ b/tests/misc/projects/Issue11582/compile.hxml.stdout @@ -0,0 +1,13 @@ +Main.hx:3: Foo +Main.hx:4: [I2,I1,Foo1] +Main.hx:5: [I2,I1,auto Foo1 (1),auto Foo1 (2),Foo2] +Main.hx:6: [I2,I1,auto Foo1 (1),auto Foo1 (2),Foo3 (1),Foo3 (2)] +Main.hx:7: [I2,I1,auto Foo1 (1),auto Foo1 (2),Foo4] +Main.hx:9: Bar +Main.hx:10: [I1,I2] +Main.hx:11: [I1,I2] +Main.hx:12: [I1,I2] +Main.hx:14: Baz +Main.hx:15: [I2,I1,I3] +Main.hx:16: [I2,I1,I3] +Main.hx:17: [I2,I1,I3] diff --git a/tests/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 diff --git a/tests/misc/src/Main.hx b/tests/misc/src/Main.hx index 7c8dc2c05cd..159277daafb 100644 --- a/tests/misc/src/Main.hx +++ b/tests/misc/src/Main.hx @@ -151,6 +151,9 @@ class Main { .filter(s -> 0 != s.indexOf('Picked up JAVA_TOOL_OPTIONS:')) .join('\n'); + content = hideStdPositions(content); + expected = hideStdPositions(expected); + 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()); @@ -170,6 +173,14 @@ class Main { return true; } + static function hideStdPositions(content:String):String { + var regex = new EReg(StringTools.replace(getStd(), '\\', '(?:\\\\|/)') + '([a-z/\\\\]+\\.hx):[0-9]+:( characters? [0-9]+(-[0-9]+)( :)?)', 'i'); + + return content.split("\n") + .map(line -> regex.replace(line, "$1:???:")) + .join("\n"); + } + static macro function getStd() { var std = Compiler.getConfiguration().stdPath; return macro $v{std.shift()}; diff --git a/tests/optimization/src/TestAnalyzer.hx b/tests/optimization/src/TestAnalyzer.hx index 2e6bfb69439..13d62011d2c 100644 --- a/tests/optimization/src/TestAnalyzer.hx +++ b/tests/optimization/src/TestAnalyzer.hx @@ -697,13 +697,13 @@ class TestAnalyzer extends TestBase { } function testIssue3869() { - var v1:Vec2 = {x: 1., y: 2.}; - var r = v1 * 2; + var v1:Vec2 = {x: 1., y: 2.}; + var r = v1 * 2; assertEqualsConst(2., r.x); assertEqualsConst(4., r.y); - var v2:Vec2 = {x: 1., y: 2.}; - var r2 = 2 * v2; + var v2:Vec2 = {x: 1., y: 2.}; + var r2 = 2 * v2; assertEqualsConst(2., r2.x); assertEqualsConst(4., r2.y); } diff --git a/tests/optimization/src/TestInlineConstructors.hx b/tests/optimization/src/TestInlineConstructors.hx index 70799c75d1b..4b9b7bcddf6 100644 --- a/tests/optimization/src/TestInlineConstructors.hx +++ b/tests/optimization/src/TestInlineConstructors.hx @@ -38,6 +38,19 @@ class NestedInlineClass { } } +class P { + public var x:Float; + + public inline function new(x = 0) + this.x = x; +} + +@:forward +abstract PA(P) to P { + public inline function new(x) + this = new P(x); +} + class TestInlineConstructors extends TestBase { @:js('return [1,2,3,3];') static function testArrayInlining() { @@ -130,4 +143,10 @@ class TestInlineConstructors extends TestBase { } return acc; } + + @:js('return [5];') + static function testForwardAbstract() { + var p2 = {v: new PA(5)}; + return [p2.v.x]; + } } diff --git a/tests/optimization/src/issues/Issue11175.hx b/tests/optimization/src/issues/Issue11175.hx new file mode 100644 index 00000000000..124d9ed983e --- /dev/null +++ b/tests/optimization/src/issues/Issue11175.hx @@ -0,0 +1,11 @@ +package issues; + +class Issue11175 { + @:js(' + throw haxe_Exception.thrown("foo"); + ') + @:analyzer(ignore) + static function test() { + throw "foo"; + } +} \ No newline at end of file diff --git a/tests/server/src/TestCase.hx b/tests/server/src/TestCase.hx index 0ca5f359631..f3b051b1f9e 100644 --- a/tests/server/src/TestCase.hx +++ b/tests/server/src/TestCase.hx @@ -6,6 +6,7 @@ import haxeserver.HaxeServerRequestResult; import haxe.display.JsonModuleTypes; import haxe.display.Display; import haxe.display.Protocol; +import haxe.display.Diagnostic; import haxe.Json; import haxeserver.process.HaxeServerProcessNode; import haxeserver.HaxeServerAsync; @@ -17,7 +18,12 @@ using StringTools; using Lambda; @:autoBuild(utils.macro.BuildHub.build()) +#if haxe_next +interface ITestCase {} +class TestCase implements ITest implements ITestCase { +#else class TestCase implements ITest { +#end static public var debugLastResult:{ hasError:Bool, stdout:String, @@ -169,6 +175,11 @@ class TestCase implements ITest { return haxe.Json.parse(lastResult.stderr).result; } + function parseDiagnostics():Array> { + var result = haxe.Json.parse(lastResult.stderr)[0]; + return if (result == null) [] else result.diagnostics; + } + function parseGotoDefinitionLocations():Array { switch parseGotoTypeDefinition().result { case null: diff --git a/tests/server/src/cases/ServerTests.hx b/tests/server/src/cases/ServerTests.hx index b9987e32f64..64b4eb375c4 100644 --- a/tests/server/src/cases/ServerTests.hx +++ b/tests/server/src/cases/ServerTests.hx @@ -3,6 +3,7 @@ package cases; import haxe.display.Display; import haxe.display.FsPath; import haxe.display.Server; +import haxe.io.Path; import utest.Assert; using StringTools; @@ -235,6 +236,110 @@ class ServerTests extends TestCase { utest.Assert.equals("function() {_Vector.Vector_Impl_.toIntVector(null);}", moreHack(type.args.statics[0].expr.testHack)); // lmao } + function testMetadata() { + var dummy_path = Path.join(["..", "misc", "projects", "Issue10844"]); + Sys.command("haxelib", ["dev", "dummy_doc_dep", Path.join([dummy_path, "dummy_doc_dep"])]); + Sys.command("haxelib", ["dev", "dummy_doc", Path.join([dummy_path, "dummy_doc"])]); + var args = ["-lib", "dummy_doc"]; + + runHaxeJsonCb(args, DisplayMethods.Metadata, {compiler: true, user: true}, function(meta) { + var analyzer = Lambda.find(meta, m -> m.name == ':analyzer'); + Assert.notNull(analyzer); + Assert.equals("Used to configure the static analyzer.", analyzer.doc); + Assert.equals("haxe compiler", analyzer.origin); + + var dummy_doc = Lambda.find(meta, m -> m.name == ':foo'); + Assert.notNull(dummy_doc); + Assert.equals("Some documentation for the @:foo metadata for cpp platform", dummy_doc.doc); + Assert.equals("dummy_doc", dummy_doc.origin); + Assert.equals(Platform.Cpp, dummy_doc.platforms[0]); + + var dummy_doc = Lambda.find(meta, m -> m.name == ':bar'); + Assert.notNull(dummy_doc); + Assert.equals("dummy_doc", dummy_doc.origin); + Assert.equals(MetadataTarget.Class, dummy_doc.targets[0]); + + var dummy_doc_dep = Lambda.find(meta, m -> m.name == ':baz'); + Assert.notNull(dummy_doc_dep); + Assert.equals("dummy_doc_dep", dummy_doc_dep.origin); + }); + + runHaxeJsonCb(args, DisplayMethods.Metadata, {compiler: true, user: false}, function(meta) { + var analyzer = Lambda.find(meta, m -> m.name == ':analyzer'); + Assert.notNull(analyzer); + + var dummy_doc = Lambda.find(meta, m -> m.name == ':foo'); + Assert.isNull(dummy_doc); + + var dummy_doc_dep = Lambda.find(meta, m -> m.name == ':baz'); + Assert.isNull(dummy_doc_dep); + }); + + runHaxeJsonCb(args, DisplayMethods.Metadata, {compiler: false, user: true}, function(meta) { + var analyzer = Lambda.find(meta, m -> m.name == ':analyzer'); + Assert.isNull(analyzer); + + var dummy_doc = Lambda.find(meta, m -> m.name == ':foo'); + Assert.notNull(dummy_doc); + + var dummy_doc_dep = Lambda.find(meta, m -> m.name == ':baz'); + Assert.notNull(dummy_doc_dep); + }); + + runHaxeJsonCb(args, DisplayMethods.Metadata, {compiler: false, user: false}, function(meta) { + Assert.equals(0, meta.length); + }); + } + + function testDefines() { + var dummy_path = Path.join(["..", "misc", "projects", "Issue10844"]); + Sys.command("haxelib", ["dev", "dummy_doc_dep", Path.join([dummy_path, "dummy_doc_dep"])]); + Sys.command("haxelib", ["dev", "dummy_doc", Path.join([dummy_path, "dummy_doc"])]); + var args = ["-lib", "dummy_doc"]; + + runHaxeJsonCb(args, DisplayMethods.Defines, {compiler: true, user: true}, function(defines) { + var debug = Lambda.find(defines, d -> d.name == 'debug'); + Assert.notNull(debug); + Assert.equals("Activated when compiling with -debug.", debug.doc); + Assert.equals("haxe compiler", debug.origin); + + var dummy_doc = Lambda.find(defines, d -> d.name == 'no-bullshit'); + Assert.notNull(dummy_doc); + Assert.equals("Only very important stuff should be compiled", dummy_doc.doc); + Assert.equals("dummy_doc", dummy_doc.origin); + + var dummy_doc_dep = Lambda.find(defines, d -> d.name == 'dummy'); + Assert.notNull(dummy_doc_dep); + Assert.equals("dummy_doc_dep", dummy_doc_dep.origin); + }); + + runHaxeJsonCb(args, DisplayMethods.Defines, {compiler: true, user: false}, function(defines) { + var debug = Lambda.find(defines, d -> d.name == 'debug'); + Assert.notNull(debug); + + var dummy_doc = Lambda.find(defines, d -> d.name == 'no-bullshit'); + Assert.isNull(dummy_doc); + + var dummy_doc_dep = Lambda.find(defines, d -> d.name == 'dummy'); + Assert.isNull(dummy_doc_dep); + }); + + runHaxeJsonCb(args, DisplayMethods.Defines, {compiler: false, user: true}, function(defines) { + var debug = Lambda.find(defines, d -> d.name == 'debug'); + Assert.isNull(debug); + + var dummy_doc = Lambda.find(defines, d -> d.name == 'no-bullshit'); + Assert.notNull(dummy_doc); + + var dummy_doc_dep = Lambda.find(defines, d -> d.name == 'dummy'); + Assert.notNull(dummy_doc_dep); + }); + + runHaxeJsonCb(args, DisplayMethods.Defines, {compiler: false, user: false}, function(defines) { + Assert.equals(0, defines.length); + }); + } + function test10986() { vfs.putContent("Main.hx", getTemplate("issues/Issue10986/Main.hx")); vfs.putContent("haxe/ds/Vector.hx", getTemplate("issues/Issue10986/Vector.hx")); diff --git a/tests/server/src/cases/issues/Issue8687.hx b/tests/server/src/cases/issues/Issue8687.hx new file mode 100644 index 00000000000..ea7934a56f9 --- /dev/null +++ b/tests/server/src/cases/issues/Issue8687.hx @@ -0,0 +1,12 @@ +package cases.issues; + +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); + } +} diff --git a/tests/server/test/templates/issues/Issue8687/Main.hx b/tests/server/test/templates/issues/Issue8687/Main.hx new file mode 100644 index 00000000000..6dce348422d --- /dev/null +++ b/tests/server/test/templates/issues/Issue8687/Main.hx @@ -0,0 +1,7 @@ +class Main { + static function main() { + trace("test"); + #if ("foo" == version("4.0.0")) + #end + } +} diff --git a/tests/unit/src/unit/issues/Issue10106.hx b/tests/unit/src/unit/issues/Issue10106.hx new file mode 100644 index 00000000000..bec7d62cf05 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue10106.hx @@ -0,0 +1,35 @@ +package unit.issues; + +class Issue10106_CExtension { + public static function fromS(cls:Class, s:String) { + return new Issue10106_C(s); + } +} + +@:using(unit.issues.Issue10106.Issue10106_CExtension) +class Issue10106_C { + public final s:String; + + public function new(s:String) { + this.s = s; + } +} + +class Issue10106_EnExtension { + public static function fromS(en:Enum, st:String):Issue10106_En { + return A; + } +} + +@:using(unit.issues.Issue10106.Issue10106_EnExtension) +enum Issue10106_En { + A; + B; +} + +class Issue10106 extends Test { + function test() { + eq(A, Issue10106_En.fromS("A")); + eq("foo", Issue10106_C.fromS("foo").s); + } +} diff --git a/tests/unit/src/unit/issues/Issue11402.hx b/tests/unit/src/unit/issues/Issue11402.hx new file mode 100644 index 00000000000..dd1b3e9e495 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11402.hx @@ -0,0 +1,78 @@ +package unit.issues; + +class Issue11402 extends Test { + static function binopWithReturn() { + var ans = Std.string(return "") + ""; + } + + static function binopWithThrow() { + var ans = Std.string(throw "") + ""; + } + + static function binopWithBreak() { + while (true) { + var ans = Std.string(break) + ""; + return "b"; + } + return "a"; + } + + static function binopWithContinue() { + var a = 0; + while (true) { + if (a++ > 0) { + return "a"; + } + var ans = Std.string(continue) + ""; + return "b"; + } + } + + static function arrayWithReturn() { + var ans = [Std.string(return "")][0]; + } + + static function arrayWithThrow() { + var ans = [Std.string(throw "")][0]; + } + + static function arrayWithBreak() { + while (true) { + var ans = [Std.string(break)][0]; + return "b"; + } + return "a"; + } + + static function arrayWithContinue() { + var a = 0; + while (true) { + if (a++ > 0) { + return "a"; + } + var ans = [Std.string(continue)][0]; + return "b"; + } + } + + static function originalExample() { + var cells = [1, 2, 3]; + var ans = ""; + ans += '${cells.length} cell${if (cells.length == 1) {return "";} else {return "s";}}.\n'; + return ans; + } + + function test() { + eq("", binopWithReturn()); + exc(binopWithThrow); + eq("a", binopWithBreak()); + eq("a", binopWithContinue()); + + eq("", arrayWithReturn()); + exc(arrayWithThrow); + eq("a", arrayWithBreak()); + eq("a", arrayWithContinue()); + + eq("s", originalExample()); + } +} 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); + } + } +} 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"))); + } +} diff --git a/tests/unit/src/unit/issues/Issue11466.hx b/tests/unit/src/unit/issues/Issue11466.hx new file mode 100644 index 00000000000..c401eb9b7bb --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11466.hx @@ -0,0 +1,30 @@ +package unit.issues; + +private function doThrow() { + throw "from doThrow"; +} + +class Issue11466 extends unit.Test { + var b = 10; + function test() { + var x = 0; + try { + x = b; + throw ''; + } catch(_) { + x += 1; + } + eq(11, x); + } + + function test2() { + var x = 0; + try { + x = b; + doThrow(); + } catch(_) { + x += 1; + } + eq(11, x); + } +} diff --git a/tests/unit/src/unit/issues/Issue11560.hx b/tests/unit/src/unit/issues/Issue11560.hx new file mode 100644 index 00000000000..ceae486d058 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue11560.hx @@ -0,0 +1,23 @@ +package unit.issues; + +@:keep +private class ParentClass { + // no field variable, the issue does not reproduce when there is one + function anyFunc() {} + + public function new() {} +} + +@:keep +private class ChildClass extends ParentClass { + var anyVar:String = null; +} + +class Issue11560 extends Test { + function test() { + var c = new ChildClass(); + + var json = haxe.Json.stringify(c, "\t"); + eq('{\n\t"anyVar": null\n}', json); + } +} diff --git a/tests/unit/src/unit/issues/Issue9174.hx b/tests/unit/src/unit/issues/Issue9174.hx new file mode 100644 index 00000000000..4f3a9f8257d --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9174.hx @@ -0,0 +1,37 @@ +package unit.issues; + +private function doThrow() { + throw "from doThrow"; +} + +class Issue9174 extends unit.Test { + function test() { + var value = ""; + try { + try { + throw "from throw"; + } catch (e:String) { + value += "inner catch"; + throw e; + } + } catch (e:String) { + value += ", outer catch, " + e; + } + eq("inner catch, outer catch, from throw", value); + } + + function test2() { + var value = ""; + try { + try { + doThrow(); + } catch (e:String) { + value += "inner catch"; + throw e; + } + } catch (e:String) { + value += ", outer catch, " + e; + } + eq("inner catch, outer catch, from doThrow", value); + } +}