Browse Source

keep `Method MethInline` for cf_kind even if inlining is disabled (#9668)

Aleksandr Kuzmenko 5 years ago
parent
commit
ea42f81f93

+ 4 - 0
src/optimization/inline.ml

@@ -6,6 +6,10 @@ open Common
 open Typecore
 open Typecore
 open Error
 open Error
 
 
+let needs_inline ctx is_extern_class cf =
+	cf.cf_kind = Method MethInline
+	&& (ctx.g.doinline || is_extern_class || has_class_field_flag cf CfExtern)
+
 let mk_untyped_call name p params =
 let mk_untyped_call name p params =
 	{
 	{
 		eexpr = TCall({ eexpr = TIdent name; etype = t_dynamic; epos = p }, params);
 		eexpr = TCall({ eexpr = TIdent name; etype = t_dynamic; epos = p }, params);

+ 22 - 12
src/optimization/inlineConstructors.ml

@@ -102,7 +102,7 @@ and inline_var = {
 	mutable iv_closed : bool (* Inline variables are marked as closed when the scope they were first assigned on ends, any appearance of this variable after it has been closed causes cancellation *)
 	mutable iv_closed : bool (* Inline variables are marked as closed when the scope they were first assigned on ends, any appearance of this variable after it has been closed causes cancellation *)
 }
 }
 
 
-and inline_object_field = 
+and inline_object_field =
 	| IOFInlineMethod of inline_object * inline_var * tclass * Type.tparams * tclass_field * tfunc
 	| IOFInlineMethod of inline_object * inline_var * tclass * Type.tparams * tclass_field * tfunc
 	| IOFInlineVar of inline_var
 	| IOFInlineVar of inline_var
 	| IOFNone
 	| IOFNone
@@ -203,15 +203,16 @@ let inline_constructors ctx original_e =
 		Returns true if there are any potential inline objects in the expression.
 		Returns true if there are any potential inline objects in the expression.
 		It is used to save work before running mark_ctors and analyze_aliases.
 		It is used to save work before running mark_ctors and analyze_aliases.
 	*)
 	*)
-	let rec check_for_ctors ?(force_inline=false) e = 
+	let rec check_for_ctors ?(force_inline=false) e =
 		let is_ctor, is_meta_inline = match e.eexpr, force_inline with
 		let is_ctor, is_meta_inline = match e.eexpr, force_inline with
 			| TMeta((Meta.Inline,_,_),_), _ ->
 			| TMeta((Meta.Inline,_,_),_), _ ->
 				false, true
 				false, true
 			| TObjectDecl _, _
 			| TObjectDecl _, _
 			| TArrayDecl _, _
 			| TArrayDecl _, _
-			| TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some ({eexpr = TFunction _})})},_,_), _
 			| TNew _, true ->
 			| TNew _, true ->
 				true, false
 				true, false
+			| TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some ({eexpr = TFunction _})} as cf)} as c,_,_), _ ->
+				Inline.needs_inline ctx c.cl_extern cf, false
 			| _ -> false, false
 			| _ -> false, false
 		in
 		in
 		is_ctor || Type.check_expr (check_for_ctors ~force_inline:is_meta_inline) e
 		is_ctor || Type.check_expr (check_for_ctors ~force_inline:is_meta_inline) e
@@ -224,15 +225,20 @@ let inline_constructors ctx original_e =
 	let rec mark_ctors ?(force_inline=false) e : texpr =
 	let rec mark_ctors ?(force_inline=false) e : texpr =
 		let is_meta_inline = match e.eexpr with (TMeta((Meta.Inline,_,_),e)) -> true | _ -> false in
 		let is_meta_inline = match e.eexpr with (TMeta((Meta.Inline,_,_),e)) -> true | _ -> false in
 		let e = Type.map_expr (mark_ctors ~force_inline:is_meta_inline) e in
 		let e = Type.map_expr (mark_ctors ~force_inline:is_meta_inline) e in
+		let mark() =
+			incr curr_io_id;
+			let id_expr = (EConst(Int (string_of_int !curr_io_id)), e.epos) in
+			let meta = (Meta.InlineObject, [id_expr], e.epos) in
+			mk (TMeta(meta, e)) e.etype e.epos
+		in
 		match e.eexpr, force_inline with
 		match e.eexpr, force_inline with
 			| TObjectDecl _, _
 			| TObjectDecl _, _
 			| TArrayDecl _, _
 			| TArrayDecl _, _
-			| TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some ({eexpr = TFunction _})})},_,_), _
 			| TNew _, true ->
 			| TNew _, true ->
-				incr curr_io_id;
-				let id_expr = (EConst(Int (string_of_int !curr_io_id)), e.epos) in
-				let meta = (Meta.InlineObject, [id_expr], e.epos) in
-				mk (TMeta(meta, e)) e.etype e.epos
+				mark()
+			| TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some ({eexpr = TFunction _})} as cf)} as c,_,_), _ ->
+				if Inline.needs_inline ctx c.cl_extern cf then mark()
+				else e
 			| _ -> e
 			| _ -> e
 	in
 	in
 
 
@@ -242,7 +248,7 @@ let inline_constructors ctx original_e =
 		The expression being analyzed should have been processed with mark_ctors before hand.
 		The expression being analyzed should have been processed with mark_ctors before hand.
 
 
 		returns: Some(inline variable) if the expression being analyzed returns an inline variable. None otherwise.
 		returns: Some(inline variable) if the expression being analyzed returns an inline variable. None otherwise.
-		
+
 		seen_ctors: used to avoid infinite constructor inlining loops.
 		seen_ctors: used to avoid infinite constructor inlining loops.
 
 
 		captured: Wether the caller is ready to accept an inline variable. If analysis results in an inline
 		captured: Wether the caller is ready to accept an inline variable. If analysis results in an inline
@@ -272,13 +278,17 @@ let inline_constructors ctx original_e =
 		let analyze_aliases_in_lvalue e = analyze_aliases seen_ctors captured true e in
 		let analyze_aliases_in_lvalue e = analyze_aliases seen_ctors captured true e in
 		let analyze_aliases_in_ctor cf captured e = analyze_aliases (cf::seen_ctors) captured false e in
 		let analyze_aliases_in_ctor cf captured e = analyze_aliases (cf::seen_ctors) captured false e in
 		let analyze_aliases captured e = analyze_aliases seen_ctors captured false e in
 		let analyze_aliases captured e = analyze_aliases seen_ctors captured false e in
-		let get_io_inline_method io fname = 
+		let get_io_inline_method io fname =
 			begin match io.io_kind with
 			begin match io.io_kind with
 			| IOKCtor(ctor) ->
 			| IOKCtor(ctor) ->
 				begin try
 				begin try
 					let f = PMap.find fname ctor.ioc_class.cl_fields in
 					let f = PMap.find fname ctor.ioc_class.cl_fields in
 					begin match f.cf_params, f.cf_kind, f.cf_expr with
 					begin match f.cf_params, f.cf_kind, f.cf_expr with
-					| [], Method MethInline, Some({eexpr = TFunction tf}) -> Some (ctor.ioc_class, ctor.ioc_tparams, f, tf)
+					| [], Method MethInline, Some({eexpr = TFunction tf}) ->
+						if Inline.needs_inline ctx ctor.ioc_class.cl_extern f then
+							Some (ctor.ioc_class, ctor.ioc_tparams, f, tf)
+						else
+							None
 					| _ -> None
 					| _ -> None
 					end
 					end
 				with Not_found -> None
 				with Not_found -> None
@@ -481,7 +491,7 @@ let inline_constructors ctx original_e =
 		| TCall(({eexpr=TField(ethis,fa)} as efield),call_args) ->
 		| TCall(({eexpr=TField(ethis,fa)} as efield),call_args) ->
 			let fname = field_name fa in
 			let fname = field_name fa in
 			let fiv = handle_field_case efield ethis fname (fun _ -> true) in
 			let fiv = handle_field_case efield ethis fname (fun _ -> true) in
-			begin match fiv with 
+			begin match fiv with
 			| IOFInlineMethod(io,io_var,c,tl,cf,tf) ->
 			| IOFInlineMethod(io,io_var,c,tl,cf,tf) ->
 				let argvs, pl = analyze_call_args call_args in
 				let argvs, pl = analyze_call_args call_args in
 				io.io_dependent_vars <- io.io_dependent_vars @ argvs;
 				io.io_dependent_vars <- io.io_dependent_vars @ argvs;

+ 1 - 1
src/optimization/optimizer.ml

@@ -304,7 +304,7 @@ let rec reduce_loop ctx e =
 				(match inl with
 				(match inl with
 				| None -> reduce_expr ctx e
 				| None -> reduce_expr ctx e
 				| Some e -> reduce_loop ctx e)
 				| Some e -> reduce_loop ctx e)
-			| {eexpr = TField(ef,(FStatic(cl,cf) | FInstance(cl,_,cf)))} when cf.cf_kind = Method MethInline && not (rec_stack_memq cf inline_stack) ->
+			| {eexpr = TField(ef,(FStatic(cl,cf) | FInstance(cl,_,cf)))} when needs_inline ctx cl.cl_extern cf && not (rec_stack_memq cf inline_stack) ->
 				begin match cf.cf_expr with
 				begin match cf.cf_expr with
 				| Some {eexpr = TFunction tf} ->
 				| Some {eexpr = TFunction tf} ->
 					let config = inline_config (Some cl) cf el e.etype in
 					let config = inline_config (Some cl) cf el e.etype in

+ 2 - 1
src/typing/calls.ml

@@ -29,7 +29,8 @@ let make_call ctx e params t ?(force_inline=false) p =
 				raise Exit
 				raise Exit
 		in
 		in
 		if not force_inline then begin
 		if not force_inline then begin
-			if f.cf_kind <> Method MethInline then raise Exit;
+			let is_extern_class = match cl with Some c -> c.cl_extern | _ -> false in
+			if not (Inline.needs_inline ctx is_extern_class f) then raise Exit;
 		end else begin
 		end else begin
 			match cl with
 			match cl with
 			| None ->
 			| None ->

+ 1 - 5
src/typing/typeloadFields.ml

@@ -567,11 +567,7 @@ let create_field_context (ctx,cctx) c cff =
 		| _ ->
 		| _ ->
 			()
 			()
 	) cff.cff_meta;
 	) cff.cff_meta;
-	let allow_inline = cctx.abstract <> None || match cff.cff_kind with
-		| FFun _ -> ctx.g.doinline || !is_extern || c.cl_extern
-		| _ -> true
-	in
-	let is_inline = allow_inline && List.mem_assoc AInline cff.cff_access in
+	let is_inline = List.mem_assoc AInline cff.cff_access in
 	let override = try Some (List.assoc AOverride cff.cff_access) with Not_found -> None in
 	let override = try Some (List.assoc AOverride cff.cff_access) with Not_found -> None in
 	let is_macro = List.mem_assoc AMacro cff.cff_access in
 	let is_macro = List.mem_assoc AMacro cff.cff_access in
 	let field_kind = match fst cff.cff_name with
 	let field_kind = match fst cff.cff_name with

+ 18 - 0
tests/server/src/cases/display/issues/Issue9266.hx

@@ -0,0 +1,18 @@
+package cases.display.issues;
+
+class Issue9266 extends DisplayTestCase {
+	/**
+		class Main {
+			static public function main() {
+				te{-1-}st;
+			}
+
+			static public inline function test() {}
+		}
+	**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Hover, {file: file, offset: offset(1)});
+		var result = parseHover().result;
+		Assert.equals('MethInline', result.item.args.field.kind.args);
+	}
+}