2
0
Эх сурвалжийг харах

[nullsafety] don't consider overridden fields safe for checking callbacks for imemdiate execution

Alexander Kuzmenko 6 жил өмнө
parent
commit
cc73ee08e7

+ 11 - 1
src/typing/nullSafety.ml

@@ -314,6 +314,16 @@ let should_be_initialized field =
 		| Var _ -> Meta.has Meta.IsVar field.cf_meta
 		| _ -> false
 
+(**
+	Check if `field` is overridden in subclasses
+*)
+let is_overridden cls field =
+	let rec loop_inheritance c =
+		(PMap.mem field.cf_name c.cl_fields)
+		|| List.exists (fun d -> loop_inheritance d) c.cl_descendants;
+	in
+	List.exists (fun d -> loop_inheritance d) cls.cl_descendants
+
 (**
 	A class which is used to check if an anonymous function passed to a method will be executed
 	before that method execution is finished.
@@ -348,7 +358,7 @@ class immediate_execution =
 							(* known to be pure *)
 							| { cl_path = ([], "Array") }, _ -> true
 							(* try to analyze function code *)
-							| _, ({ cf_expr = (Some { eexpr = TFunction fn }) } as field) ->
+							| _, ({ cf_expr = (Some { eexpr = TFunction fn }) } as field) when field.cf_final || not (is_overridden cls field) ->
 								if arg_num < 0 || arg_num >= List.length fn.tf_args then
 									false
 								else begin

+ 20 - 0
tests/nullsafety/src/cases/Test.hx

@@ -759,6 +759,14 @@ class Test {
 		}
 	}
 
+	static function closure_passedToOverriddenMethod(?a:String) {
+		var o:Parent = new Child();
+		if(a != null) {
+			cast(o, Child).childExecute(() -> a.length);
+			o.execute(() -> shouldFail(a.length));
+		}
+	}
+
 	static function recursiveTypedef_shouldNotCrashTheCompiler(a:Recursive<Void>, b:Recursive<Void>) {
 		a = b;
 	}
@@ -772,3 +780,15 @@ typedef Recursive<T1> = {
 // class RecClass<T1> {
 // 	public function rec<T2>(a:Recursive<T1>):Recursive<T2> return a;
 // }
+
+private class Parent {
+	public function new() {}
+
+	public function execute(cb:()->Void) cb();
+}
+
+private class Child extends Parent {
+	static var tmp:Any = '';
+	override public function execute(cb:()->Void) tmp = cb;
+	public function childExecute(cb:()->Void) cb();
+}