Browse Source

[nullsafety] allow passing nullable to dynamic (#9588, closes #10272, closes #10276)

Aleksandr Kuzmenko 4 years ago
parent
commit
fe23a92264
2 changed files with 32 additions and 20 deletions
  1. 15 20
      src/typing/nullSafety.ml
  2. 17 0
      tests/nullsafety/src/cases/TestStrict.hx

+ 15 - 20
src/typing/nullSafety.ml

@@ -70,19 +70,32 @@ let is_string_type t =
 (**
 (**
 	Check for explicit `Null<>` typing
 	Check for explicit `Null<>` typing
 *)
 *)
-let rec is_nullable_type = function
+let rec is_nullable_type ?(dynamic_is_nullable=false) = function
 	| TMono r ->
 	| TMono r ->
 		(match r.tm_type with None -> false | Some t -> is_nullable_type t)
 		(match r.tm_type with None -> false | Some t -> is_nullable_type t)
 	| TAbstract ({ a_path = ([],"Null") },[t]) ->
 	| TAbstract ({ a_path = ([],"Null") },[t]) ->
 		true
 		true
+	| TAbstract ({ a_path = ([],"Any") },[]) ->
+		false
 	| TAbstract (a,tl) when not (Meta.has Meta.CoreType a.a_meta) ->
 	| TAbstract (a,tl) when not (Meta.has Meta.CoreType a.a_meta) ->
 		is_nullable_type (apply_params a.a_params tl a.a_this)
 		is_nullable_type (apply_params a.a_params tl a.a_this)
 	| TLazy f ->
 	| TLazy f ->
 		is_nullable_type (lazy_type f)
 		is_nullable_type (lazy_type f)
 	| TType (t,tl) ->
 	| TType (t,tl) ->
 		is_nullable_type (apply_typedef t tl)
 		is_nullable_type (apply_typedef t tl)
+	| (TDynamic _) as t ->
+		dynamic_is_nullable && t == t_dynamic
 	| _ ->
 	| _ ->
 		false
 		false
+(*
+(**
+	Check if `callee` represents `trace`
+*)
+let is_trace_expr callee =
+	match callee.eexpr with
+	| TIdent "`trace" -> true
+	| _ -> false *)
+
 
 
 (**
 (**
 	If `expr` is a TCast or TMeta, returns underlying expression (recursively bypassing nested casts).
 	If `expr` is a TCast or TMeta, returns underlying expression (recursively bypassing nested casts).
@@ -358,23 +371,6 @@ let accessed_field_name access =
 		| FClosure (_, { cf_name = name }) -> name
 		| FClosure (_, { cf_name = name }) -> name
 		| FEnum (_, { ef_name = name }) -> name
 		| FEnum (_, { ef_name = name }) -> name
 
 
-let rec can_pass_type src dst =
-	if is_nullable_type src && not (is_nullable_type dst) then
-		false
-	else
-		(* TODO *)
-		match dst with
-			| TMono r -> (match r.tm_type with None -> true | Some t -> can_pass_type src t)
-			| TEnum (_, params) -> true
-			| TInst _ -> true
-			| TType (t, tl) -> can_pass_type src (apply_typedef t tl)
-			| TFun _ -> true
-			| TAnon _ -> true
-			| TDynamic _ -> true
-			| TLazy _ -> true
-			| TAbstract ({ a_path = ([],"Null") }, [t]) -> true
-			| TAbstract _ -> true
-
 (**
 (**
 	Collect nullable local vars which are checked against `null`.
 	Collect nullable local vars which are checked against `null`.
 	Returns a tuple of (vars_checked_to_be_null * vars_checked_to_be_not_null) in case `condition` evaluates to `true`.
 	Returns a tuple of (vars_checked_to_be_null * vars_checked_to_be_not_null) in case `condition` evaluates to `true`.
@@ -1106,7 +1102,7 @@ class expr_checker mode immediate_execution report =
 							with Not_found -> false)
 							with Not_found -> false)
 						fields
 						fields
 				| _, _ ->
 				| _, _ ->
-					if self#is_nullable_expr expr && not (is_nullable_type to_type) then
+					if self#is_nullable_expr expr && not (is_nullable_type ~dynamic_is_nullable:true to_type) then
 						false
 						false
 					else begin
 					else begin
 						let expr_type = unfold_null expr.etype in
 						let expr_type = unfold_null expr.etype in
@@ -1120,7 +1116,6 @@ class expr_checker mode immediate_execution report =
 								true
 								true
 							| e ->
 							| e ->
 								fail ~msg:"Null safety unification failure" expr.epos __POS__
 								fail ~msg:"Null safety unification failure" expr.epos __POS__
-						(* can_pass_type expr.etype to_type *)
 					end
 					end
 		(**
 		(**
 			Should be called for the root expressions of a method or for then initialization expressions of fields.
 			Should be called for the root expressions of a method or for then initialization expressions of fields.

+ 17 - 0
tests/nullsafety/src/cases/TestStrict.hx

@@ -1008,6 +1008,23 @@ class TestStrict {
 			}
 			}
 		];
 		];
 	}
 	}
+
+	static function issue9588_DynamicIsNullable_AnyIsNotNullable(?a:String) {
+		function dyn(v:Dynamic):Dynamic
+			return v;
+		var d:Dynamic = dyn(a);
+		// TODO: decide if 'dynamic to non-nullable' should fail since we allow 'nullable to dynamic now'.
+		//shouldFail(var s:String = d);
+
+		function any(v:Any):Any
+			return v;
+		shouldFail(any(a));
+		var s:String = any('');
+	}
+
+	static function issue10272_nullableConcatString_shouldPass(msg:Null<Dynamic>) {
+		trace("Message: " + msg);
+	}
 }
 }
 
 
 private class FinalNullableFields {
 private class FinalNullableFields {