From 3f13b750ba4ce1bfd52983b3c2247d010cb1f176 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Mon, 5 Feb 2024 08:23:45 +0100 Subject: [PATCH] Make ctx.pass immutable (#11538) * remove @:enumConstructorParam * remove init_class_done see if this breaks anything * clone for expr * make ctx.pass immutable * ctx.e can be immutable too * add failing test to show everyone that it's broken * fix it * inherit allow_inline and allow_transform to contexts within the same module --- src-json/meta.json | 7 ---- src/codegen/gencommon/normalize.ml | 2 +- src/context/typecore.ml | 39 ++++++++----------- src/typing/functionArguments.ml | 16 ++++---- src/typing/macroContext.ml | 28 ++++++------- src/typing/typeload.ml | 1 - src/typing/typeloadFields.ml | 19 +++++---- src/typing/typeloadFunction.ml | 3 -- src/typing/typer.ml | 26 ++++++------- src/typing/typerDisplay.ml | 1 - tests/misc/projects/Issue11538/M.hx | 3 ++ tests/misc/projects/Issue11538/Main.hx | 25 ++++++++++++ tests/misc/projects/Issue11538/compile.hxml | 2 + .../projects/Issue11538/compile.hxml.stdout | 1 + 14 files changed, 97 insertions(+), 76 deletions(-) create mode 100644 tests/misc/projects/Issue11538/M.hx create mode 100644 tests/misc/projects/Issue11538/Main.hx create mode 100644 tests/misc/projects/Issue11538/compile.hxml create mode 100644 tests/misc/projects/Issue11538/compile.hxml.stdout diff --git a/src-json/meta.json b/src-json/meta.json index 9df0fb365e6..8d5d7b9e1f6 100644 --- a/src-json/meta.json +++ b/src-json/meta.json @@ -295,13 +295,6 @@ "targets": ["TAbstract"], "links": ["https://haxe.org/manual/types-abstract-enum.html"] }, - { - "name": "EnumConstructorParam", - "metadata": ":enumConstructorParam", - "doc": "Used internally to annotate GADT type parameters.", - "targets": ["TClass"], - "internal": true - }, { "name": "Event", "metadata": ":event", diff --git a/src/codegen/gencommon/normalize.ml b/src/codegen/gencommon/normalize.ml index 2758423ef55..5072a609734 100644 --- a/src/codegen/gencommon/normalize.ml +++ b/src/codegen/gencommon/normalize.ml @@ -31,7 +31,7 @@ open Gencommon let rec filter_param (stack:t list) t = match t with - | TInst({ cl_kind = KTypeParameter _ } as c,_) when Meta.has Meta.EnumConstructorParam c.cl_meta -> + | TInst({ cl_kind = KTypeParameter ttp },_) when ttp.ttp_host = TPHEnumConstructor -> t_dynamic | TMono r -> (match r.tm_type with diff --git a/src/context/typecore.ml b/src/context/typecore.ml index 730c05259b8..b0db1b0ff73 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -169,8 +169,8 @@ and typer = { mutable m : typer_module; c : typer_class; f : typer_field; - mutable e : typer_expr; - mutable pass : typer_pass; + e : typer_expr; + pass : typer_pass; mutable type_params : type_params; mutable allow_inline : bool; mutable allow_transform : bool; @@ -183,7 +183,7 @@ and monomorphs = { } module TyperManager = struct - let create com g m c f e pass params = { + let create com g m c f e pass params allow_inline allow_transform = { com = com; g = g; t = com.basic; @@ -192,8 +192,8 @@ module TyperManager = struct f = f; e = e; pass = pass; - allow_inline = true; - allow_transform = true; + allow_inline; + allow_transform; type_params = params; memory_marker = memory_marker; } @@ -244,42 +244,46 @@ module TyperManager = struct let c = create_ctx_c null_class in let f = create_ctx_f null_field in let e = create_ctx_e () in - create com g m c f e PBuildModule [] + create com g m c f e PBuildModule [] true true let clone_for_class ctx c = let c = create_ctx_c c in let f = create_ctx_f null_field in let e = create_ctx_e () in let params = match c.curclass.cl_kind with KAbstractImpl a -> a.a_params | _ -> c.curclass.cl_params in - create ctx.com ctx.g ctx.m c f e PBuildClass params + create ctx.com ctx.g ctx.m c f e PBuildClass params ctx.allow_inline ctx.allow_transform let clone_for_enum ctx en = let c = create_ctx_c null_class in let f = create_ctx_f null_field in let e = create_ctx_e () in - create ctx.com ctx.g ctx.m c f e PBuildModule en.e_params + create ctx.com ctx.g ctx.m c f e PBuildModule en.e_params ctx.allow_inline ctx.allow_transform let clone_for_typedef ctx td = let c = create_ctx_c null_class in let f = create_ctx_f null_field in let e = create_ctx_e () in - create ctx.com ctx.g ctx.m c f e PBuildModule td.t_params + create ctx.com ctx.g ctx.m c f e PBuildModule td.t_params ctx.allow_inline ctx.allow_transform let clone_for_abstract ctx a = let c = create_ctx_c null_class in let f = create_ctx_f null_field in let e = create_ctx_e () in - create ctx.com ctx.g ctx.m c f e PBuildModule a.a_params + create ctx.com ctx.g ctx.m c f e PBuildModule a.a_params ctx.allow_inline ctx.allow_transform let clone_for_field ctx cf params = let f = create_ctx_f cf in let e = create_ctx_e () in - create ctx.com ctx.g ctx.m ctx.c f e PBuildClass params + create ctx.com ctx.g ctx.m ctx.c f e PBuildClass params ctx.allow_inline ctx.allow_transform let clone_for_enum_field ctx params = let f = create_ctx_f null_field in let e = create_ctx_e () in - create ctx.com ctx.g ctx.m ctx.c f e PBuildClass params + create ctx.com ctx.g ctx.m ctx.c f e PBuildClass params ctx.allow_inline ctx.allow_transform + + let clone_for_expr ctx = + let e = create_ctx_e () in + create ctx.com ctx.g ctx.m ctx.c ctx.f e PTypeField ctx.type_params ctx.allow_inline ctx.allow_transform end type field_host = @@ -559,12 +563,8 @@ let rec flush_pass ctx p where = let make_pass ctx f = f -let init_class_done ctx = - ctx.pass <- PConnectField - let enter_field_typing_pass ctx info = - flush_pass ctx PConnectField info; - ctx.pass <- PTypeField + flush_pass ctx PConnectField info let make_lazy ?(force=true) ctx t_proc f where = let r = ref (lazy_available t_dynamic) in @@ -909,11 +909,6 @@ let debug com (path : string list) str = if List.exists (Ast.match_path false path) debug_paths then emit(); end -let init_class_done ctx = - let path = fst ctx.c.curclass.cl_path @ [snd ctx.c.curclass.cl_path] in - debug ctx.com path ("init_class_done " ^ s_type_path ctx.c.curclass.cl_path); - init_class_done ctx - let ctx_pos ctx = let inf = fst ctx.m.curmod.m_path @ [snd ctx.m.curmod.m_path]in let inf = (match snd ctx.c.curclass.cl_path with "" -> inf | n when n = snd ctx.m.curmod.m_path -> inf | n -> inf @ [n]) in diff --git a/src/typing/functionArguments.ml b/src/typing/functionArguments.ml index cba9c2add66..f7251a69ca3 100644 --- a/src/typing/functionArguments.ml +++ b/src/typing/functionArguments.ml @@ -4,7 +4,7 @@ open Type open Typecore open Error -let type_function_arg ctx t e opt p = +let type_function_arg com t e opt p = (* TODO https://github.com/HaxeFoundation/haxe/issues/8461 *) (* delay ctx PTypeField (fun() -> if ExtType.is_void (follow t) then @@ -12,9 +12,9 @@ let type_function_arg ctx t e opt p = ); *) if opt then let e = (match e with None -> Some (EConst (Ident "null"),null_pos) | _ -> e) in - ctx.t.tnull t, e + com.Common.basic.tnull t, e else - let t = match e with Some (EConst (Ident "null"),null_pos) -> ctx.t.tnull t | _ -> t in + let t = match e with Some (EConst (Ident "null"),null_pos) -> com.basic.tnull t | _ -> t in t, e let type_function_arg_value ctx t c do_display = @@ -38,7 +38,7 @@ let type_function_arg_value ctx t c do_display = loop e class function_arguments - (ctx : typer) + (com : Common.context) (type_arg : int -> bool -> type_hint option -> pos -> Type.t) (is_extern : bool) (do_display : bool) @@ -48,7 +48,7 @@ class function_arguments let with_default = let l = List.mapi (fun i ((name,pn),opt,_,t,eo) -> let t = type_arg i opt t pn in - let t,eo = type_function_arg ctx t eo opt pn in + let t,eo = type_function_arg com t eo opt pn in (name,eo,t) ) syntax in let l = match abstract_this with @@ -83,7 +83,7 @@ object(self) (* Returns the `(tvar * texpr option) list` for `tf_args`. Also checks the validity of argument names and whether or not an argument should be displayed. *) - method for_expr = match expr_repr with + method for_expr ctx = match expr_repr with | Some l -> l | None -> @@ -116,7 +116,7 @@ object(self) l (* Verifies the validity of any argument typed as `haxe.extern.Rest` and checks default values. *) - method verify_extern = + method verify_extern ctx = let rec loop is_abstract_this syntax typed = match syntax,typed with | syntax,(name,_,t) :: typed when is_abstract_this -> loop false syntax typed @@ -135,5 +135,5 @@ object(self) method bring_into_context ctx = List.iter (fun (v,_) -> ctx.f.locals <- PMap.add v.v_name v ctx.f.locals - ) self#for_expr + ) (self#for_expr ctx) end diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index b17f1a2b103..225c211339d 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -57,7 +57,7 @@ let macro_timer com l = let typing_timer ctx need_type f = let t = Timer.timer ["typing"] in - let old = ctx.com.error_ext and oldp = ctx.pass and oldlocals = ctx.f.locals in + let old = ctx.com.error_ext and oldlocals = ctx.f.locals in let restore_report_mode = disable_report_mode ctx.com in (* disable resumable errors... unless we are in display mode (we want to reach point of completion) @@ -65,18 +65,20 @@ let typing_timer ctx need_type f = (* if ctx.com.display.dms_kind = DMNone then ctx.com.error <- (fun e -> raise_error e); *) (* TODO: review this... *) ctx.com.error_ext <- (fun err -> raise_error { err with err_from_macro = true }); - if need_type && ctx.pass < PTypeField then begin + let ctx = if need_type && ctx.pass < PTypeField then begin enter_field_typing_pass ctx ("typing_timer",[] (* TODO: ? *)); - end; + TyperManager.clone_for_expr ctx + end else + ctx + in let exit() = t(); ctx.com.error_ext <- old; - ctx.pass <- oldp; ctx.f.locals <- oldlocals; restore_report_mode (); in try - let r = f() in + let r = f ctx in exit(); r with Error err -> @@ -322,7 +324,7 @@ let make_macro_api ctx mctx p = { com_api with MacroApi.get_type = (fun s -> - typing_timer ctx false (fun() -> + typing_timer ctx false (fun ctx -> let path = parse_path s in let tp = match List.rev (fst path) with | s :: sl when String.length s > 0 && (match s.[0] with 'A'..'Z' -> true | _ -> false) -> @@ -338,10 +340,10 @@ let make_macro_api ctx mctx p = ) ); MacroApi.resolve_type = (fun t p -> - typing_timer ctx false (fun() -> Typeload.load_complex_type ctx false (t,p)) + typing_timer ctx false (fun ctx -> Typeload.load_complex_type ctx false (t,p)) ); MacroApi.resolve_complex_type = (fun t -> - typing_timer ctx false (fun() -> + typing_timer ctx false (fun ctx -> let rec load (t,_) = ((match t with | CTPath ptp -> @@ -394,17 +396,17 @@ let make_macro_api ctx mctx p = ) ); MacroApi.get_module = (fun s -> - typing_timer ctx false (fun() -> + typing_timer ctx false (fun ctx -> let path = parse_path s in let m = List.map type_of_module_type (TypeloadModule.load_module ctx path p).m_types in m ) ); MacroApi.type_expr = (fun e -> - typing_timer ctx true (fun() -> type_expr ctx e WithType.value) + typing_timer ctx true (fun ctx -> type_expr ctx e WithType.value) ); MacroApi.flush_context = (fun f -> - typing_timer ctx true f + typing_timer ctx true (fun _ -> f ()) ); MacroApi.get_local_type = (fun() -> match ctx.c.get_build_infos() with @@ -500,7 +502,7 @@ let make_macro_api ctx mctx p = end ); MacroApi.module_dependency = (fun mpath file -> - let m = typing_timer ctx false (fun() -> + let m = typing_timer ctx false (fun ctx -> let old_deps = ctx.m.curmod.m_extra.m_deps in let m = TypeloadModule.load_module ctx (parse_path mpath) p in ctx.m.curmod.m_extra.m_deps <- old_deps; @@ -512,7 +514,7 @@ let make_macro_api ctx mctx p = ctx.m.curmod ); MacroApi.cast_or_unify = (fun t e p -> - typing_timer ctx true (fun () -> + typing_timer ctx true (fun ctx -> try ignore(AbstractCast.cast_or_unify_raise ctx t e p); true diff --git a/src/typing/typeload.ml b/src/typing/typeload.ml index 7bc27105321..bfba81c88ac 100644 --- a/src/typing/typeload.ml +++ b/src/typing/typeload.ml @@ -726,7 +726,6 @@ let rec type_type_param ctx host path p tp = 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 p tp.tp_params; c.cl_meta <- tp.Ast.tp_meta; - if host = TPHEnumConstructor then c.cl_meta <- (Meta.EnumConstructorParam,[],null_pos) :: c.cl_meta; let ttp = mk_type_param c host None None in if ctx.m.is_display_file && DisplayPosition.display_position#enclosed_in (pos tp.tp_name) then DisplayEmitter.display_type ctx ttp.ttp_type (pos tp.tp_name); diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index f49140384ff..200470095e2 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -740,10 +740,11 @@ module TypeBinding = struct display_error ctx.com ("Redefinition of variable " ^ cf.cf_name ^ " in subclass is not allowed. Previously declared at " ^ (s_type_path csup.cl_path) ) cf.cf_name_pos end - let bind_var_expression ctx cctx fctx cf e = + let bind_var_expression ctx_f cctx fctx cf e = let c = cctx.tclass in let t = cf.cf_type in let p = cf.cf_pos in + let ctx = TyperManager.clone_for_expr ctx_f in if (has_class_flag c CInterface) then unexpected_expression ctx.com fctx "Initialization on field of interface" (pos e); cf.cf_meta <- ((Meta.Value,[e],null_pos) :: cf.cf_meta); let check_cast e = @@ -834,8 +835,9 @@ module TypeBinding = struct | Some e -> bind_var_expression ctx cctx fctx cf e - let bind_method ctx cctx fctx cf t args ret e p = + let bind_method ctx_f cctx fctx cf t args ret e p = let c = cctx.tclass in + let ctx = TyperManager.clone_for_expr ctx_f in let bind r = incr stats.s_methods_typed; if (Meta.has (Meta.Custom ":debug.typing") (c.cl_meta @ cf.cf_meta)) then ctx.com.print (Printf.sprintf "Typing method %s.%s\n" (s_type_path c.cl_path) cf.cf_name); @@ -875,7 +877,7 @@ module TypeBinding = struct if v.v_name <> "_" && has_mono v.v_type then warning ctx WTemp "Uninferred function argument, please add a type-hint" v.v_pos; ) fargs; *) let tf = { - tf_args = args#for_expr; + tf_args = args#for_expr ctx; tf_type = ret; tf_expr = e; } in @@ -1192,7 +1194,7 @@ let setup_args_ret ctx cctx fctx name fd p = in if i = 0 then maybe_use_property_type cto (fun () -> match Lazy.force mk with MKSetter -> true | _ -> false) def else def() in - let args = new FunctionArguments.function_arguments ctx type_arg is_extern fctx.is_display_field abstract_this fd.f_args in + let args = new FunctionArguments.function_arguments ctx.com type_arg is_extern fctx.is_display_field abstract_this fd.f_args in args,ret let create_method (ctx,cctx,fctx) c f fd p = @@ -1346,11 +1348,15 @@ let create_method (ctx,cctx,fctx) c f fd p = if fctx.is_display_field then begin delay ctx PTypeField (fun () -> (* We never enter type_function so we're missing out on the argument processing there. Let's do it here. *) - ignore(args#for_expr) + let ctx = TyperManager.clone_for_expr ctx in + ignore(args#for_expr ctx) ); check_field_display ctx fctx c cf; end else - delay ctx PTypeField (fun () -> args#verify_extern); + delay ctx PTypeField (fun () -> + let ctx = TyperManager.clone_for_expr ctx in + args#verify_extern ctx + ); if fd.f_expr <> None then begin if fctx.is_abstract then unexpected_expression ctx.com fctx "Abstract methods may not have an expression" p else if not (fctx.is_inline || fctx.is_macro) then warning ctx WExternWithExpr "Extern non-inline function may not have an expression" p; @@ -1608,7 +1614,6 @@ let check_overloads ctx c = let finalize_class cctx = (* push delays in reverse order so they will be run in correct order *) List.iter (fun (ctx,r) -> - init_class_done ctx; (match r with | None -> () | Some r -> delay ctx PTypeField (fun() -> ignore(lazy_type r))) diff --git a/src/typing/typeloadFunction.ml b/src/typing/typeloadFunction.ml index d3dff29cd54..9e8b073b3c6 100644 --- a/src/typing/typeloadFunction.ml +++ b/src/typing/typeloadFunction.ml @@ -28,12 +28,9 @@ open Error open FunctionArguments let save_field_state ctx = - let old_e = ctx.e in - ctx.e <- TyperManager.create_ctx_e (); let locals = ctx.f.locals in (fun () -> ctx.f.locals <- locals; - ctx.e <- old_e; ) let type_function_params ctx fd host fname p = diff --git a/src/typing/typer.ml b/src/typing/typer.ml index 57778ec4f16..25e48f28733 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -1217,23 +1217,30 @@ and type_map_declaration ctx e1 el with_type p = let el = (mk (TVar (v,Some enew)) t_dynamic p) :: (List.rev el) in mk (TBlock el) tmap p -and type_local_function ctx kind f with_type p = +and type_local_function ctx_from 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 TPHLocal (match name with None -> "localfun" | Some (n,_) -> n) p in + let params = TypeloadFunction.type_function_params ctx_from 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 name = None then display_error ctx_from.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 end; let v,pname = (match name with | None -> None,p | Some (v,pn) -> Some v,pn ) in - let old_tp,old_in_loop = ctx.type_params,ctx.e.in_loop in + let curfun = match ctx_from.e.curfun with + | FunStatic -> FunStatic + | FunMemberAbstract + | FunMemberAbstractLocal -> FunMemberAbstractLocal + | _ -> FunMemberClassLocal + in + let ctx = TyperManager.clone_for_expr ctx_from in + let old_tp = ctx.type_params in ctx.type_params <- params @ ctx.type_params; if not inline then ctx.e.in_loop <- false; let rt = Typeload.load_type_hint ctx p f.f_type in let type_arg _ opt t p = Typeload.load_type_hint ~opt ctx p t in - let args = new FunctionArguments.function_arguments ctx type_arg false ctx.f.in_display None f.f_args in + let args = new FunctionArguments.function_arguments ctx.com type_arg false ctx.f.in_display None f.f_args in let targs = args#for_type in let maybe_unify_arg t1 t2 = match follow t1 with @@ -1331,17 +1338,10 @@ and type_local_function ctx kind f with_type p = if params <> [] then v.v_extra <- Some (var_extra params None); Some v ) in - let curfun = match ctx.e.curfun with - | FunStatic -> FunStatic - | FunMemberAbstract - | FunMemberAbstractLocal -> FunMemberAbstractLocal - | _ -> FunMemberClassLocal - in let e = TypeloadFunction.type_function ctx args rt curfun f.f_expr ctx.f.in_display p in ctx.type_params <- old_tp; - ctx.e.in_loop <- old_in_loop; let tf = { - tf_args = args#for_expr; + tf_args = args#for_expr ctx; tf_type = rt; tf_expr = e; } in diff --git a/src/typing/typerDisplay.ml b/src/typing/typerDisplay.ml index 9470e8bae60..7734c359d90 100644 --- a/src/typing/typerDisplay.ml +++ b/src/typing/typerDisplay.ml @@ -583,7 +583,6 @@ let handle_display ctx e_ast dk mode with_type = raise_toplevel ctx dk with_type (s_type_path path,p) | DisplayException(DisplayFields ({fkind = CRTypeHint} as r)) when (match fst e_ast with ENew _ -> true | _ -> false) -> let timer = Timer.timer ["display";"toplevel";"filter ctors"] in - ctx.pass <- PBuildClass; let l = List.filter (fun item -> let is_private_to_current_module mt = (* Remove the _Module nonsense from the package *) diff --git a/tests/misc/projects/Issue11538/M.hx b/tests/misc/projects/Issue11538/M.hx new file mode 100644 index 00000000000..e9d9ac1c27a --- /dev/null +++ b/tests/misc/projects/Issue11538/M.hx @@ -0,0 +1,3 @@ +class M { + static public var x:Float; +} diff --git a/tests/misc/projects/Issue11538/Main.hx b/tests/misc/projects/Issue11538/Main.hx new file mode 100644 index 00000000000..58d58e3cb93 --- /dev/null +++ b/tests/misc/projects/Issue11538/Main.hx @@ -0,0 +1,25 @@ +import haxe.macro.Context; +import haxe.macro.Expr; + +using haxe.macro.Tools; + +#if !macro +@:build(Main.build()) +#end +class Main { + #if macro + static function build():Array { + var t = Context.typeof(macro M.x); + var field = (macro class X { + static public var type = $v{t.toString()}; + }).fields[0]; + return [field]; + } + #end +} + +function main() { + #if !macro + trace(Main.type); + #end +} diff --git a/tests/misc/projects/Issue11538/compile.hxml b/tests/misc/projects/Issue11538/compile.hxml new file mode 100644 index 00000000000..b30a755894b --- /dev/null +++ b/tests/misc/projects/Issue11538/compile.hxml @@ -0,0 +1,2 @@ +--main Main +--interp \ No newline at end of file diff --git a/tests/misc/projects/Issue11538/compile.hxml.stdout b/tests/misc/projects/Issue11538/compile.hxml.stdout new file mode 100644 index 00000000000..b41a42411d0 --- /dev/null +++ b/tests/misc/projects/Issue11538/compile.hxml.stdout @@ -0,0 +1 @@ +Main.hx:23: Float \ No newline at end of file