Browse Source

Default value for abstracts (#12351)

* add a_default

* let's see what's broken

* fix what's broken

* Add default value to more target specific sized ints

* macro encoder for abstract default value

* Have a go at a hxb reader and writer

* update abstract printer

* remove coroutine test

will be added back to the coroutine branch later

---------

Co-authored-by: Simon Krajewski <[email protected]>
Aidan Lee 2 weeks ago
parent
commit
bb569d9b99

+ 7 - 0
src-json/meta.json

@@ -180,6 +180,13 @@
 		"doc": "",
 		"platforms": ["cpp"]
 	},
+	{
+		"name": "DefaultValue",
+		"metadata": ":defaultValue",
+		"doc": "Default value for abstracts",
+		"targets": ["TAbstract"],
+		"internal": true
+	},
 	{
 		"name": "DefParam",
 		"metadata": ":defParam",

+ 4 - 0
src/compiler/hxb/hxbReader.ml

@@ -1583,6 +1583,10 @@ class hxb_reader
 		a.a_write <- self#read_option (fun () -> self#read_field_ref);
 		a.a_call <- self#read_option (fun () -> self#read_field_ref);
 		a.a_constructor <- self#read_option (fun () -> self#read_field_ref);
+		a.a_default <- self#read_option (fun () -> 
+			let fctx = self#start_texpr in
+			let e = self#read_texpr fctx in
+			Lazy.from_val e);
 
 		a.a_ops <- self#read_list (fun () ->
 			let i = read_byte ch in

+ 8 - 1
src/compiler/hxb/hxbWriter.ml

@@ -1949,10 +1949,17 @@ module HxbWriter = struct
 		in
 
 		Chunk.write_list writer.chunk a.a_array (write_field_ref writer c CfrStatic);
-		Chunk.write_option writer.chunk a.a_read (write_field_ref writer c CfrStatic );
+		Chunk.write_option writer.chunk a.a_read (write_field_ref writer c CfrStatic);
 		Chunk.write_option writer.chunk a.a_write (write_field_ref writer c CfrStatic);
 		Chunk.write_option writer.chunk a.a_call (write_field_ref writer c CfrStatic);
 		Chunk.write_option writer.chunk a.a_constructor (write_field_ref writer c CfrStatic);
+		Chunk.write_option writer.chunk a.a_default (fun lazy_texpr ->
+			let texpr = Lazy.force lazy_texpr in
+			let fctx,close = start_texpr writer texpr.epos in
+			catch_unbound_ttp (fun () -> write_texpr writer fctx texpr) "default value" None;
+			let expr_pre_chunk,expr_chunk = close() in
+			Chunk.export_data expr_pre_chunk writer.chunk;
+			Chunk.export_data expr_chunk writer.chunk);
 
 		Chunk.write_list writer.chunk a.a_ops (fun (op, cf) ->
 			Chunk.write_u8 writer.chunk (binop_index op);

+ 1 - 0
src/core/tFunctions.ml

@@ -302,6 +302,7 @@ let null_abstract = {
 	a_constructor = None;
 	a_extern = false;
 	a_enum = false;
+	a_default = None;
 }
 
 let create_dependency mdep origin =

+ 1 - 0
src/core/tOther.ml

@@ -304,6 +304,7 @@ let mk_abstract m path pos name_pos =
 		a_extern = false;
 		a_enum = false;
 		a_call = None;
+		a_default = None;
 	}
 
 module TClass = struct

+ 1 - 0
src/core/tPrinting.ml

@@ -593,6 +593,7 @@ module Printer = struct
 			"a_array",s_list ", " (fun cf -> cf.cf_name) a.a_array;
 			"a_read",s_opt (fun cf -> cf.cf_name) a.a_read;
 			"a_write",s_opt (fun cf -> cf.cf_name) a.a_write;
+			"a_default",s_opt (fun lazy_texpr -> lazy_texpr |> Lazy.force |> s_expr_ast true "" s_type) a.a_default;
 		]
 
 	let s_tvar_extra ve =

+ 1 - 0
src/core/tType.ml

@@ -398,6 +398,7 @@ and tabstract = {
 	mutable a_constructor : tclass_field option;
 	mutable a_extern : bool;
 	mutable a_enum : bool;
+	mutable a_default : texpr Lazy.t option;
 }
 
 and module_type =

+ 10 - 8
src/core/texpr.ml

@@ -547,15 +547,17 @@ module Builder = struct
 	let index basic e index t p =
 		mk (TArray (e,mk (TConst (TInt (Int32.of_int index))) basic.tint p)) t p
 
-	let default_value t p = match follow_without_null t with
-		| TAbstract({a_path = ([],"Int")},[]) ->
-			mk (TConst (TInt (Int32.zero))) t p
-		| TAbstract({a_path = ([],"Float")},[]) ->
-			mk (TConst (TFloat "0.0")) t p
-		| TAbstract({a_path = ([],"Bool")},[]) ->
-			mk (TConst (TBool false)) t p
-		| _ ->
+	let rec default_value t p = match t with
+		| TAbstract({a_default = Some f},_) ->
+			{(Lazy.force f) with etype = t; epos = p}
+		| TInst _ | TEnum _ | TAbstract _ | TFun _ | TAnon _ | TDynamic _ | TMono {tm_type = None} ->
 			mk (TConst TNull) t p
+		| TLazy r ->
+			default_value (lazy_type r) p
+		| TMono {tm_type = Some t} ->
+			default_value t p
+		| TType(td,tl) ->
+			default_value (apply_typedef td tl) p
 
 	let resolve_and_make_static_call c name args p =
 		ignore(c.cl_build());

+ 2 - 1
src/macro/macroApi.ml

@@ -1083,7 +1083,8 @@ and encode_tabstract a =
 		"to", encode_array ((List.map (fun t -> encode_obj [ "t",encode_type t; "field",vnull]) a.a_to) @ (List.map (fun (t,cf) -> encode_obj [ "t",encode_type t; "field",encode_cfield cf]) a.a_to_field));
 		"array", encode_array (List.map encode_cfield a.a_array);
 		"resolve", (match a.a_read with None -> vnull | Some cf -> encode_cfref cf);
-		"resolveWrite", (match a.a_write with None -> vnull | Some cf -> encode_cfref cf)
+		"resolveWrite", (match a.a_write with None -> vnull | Some cf -> encode_cfref cf);
+		"defaultValue", (match a.a_default with None -> vnull | Some lazy_texpr -> encode_ref lazy_texpr (fun lazy_texpr -> lazy_texpr |> Lazy.force |> encode_texpr) (fun () -> "default value") )
 	]
 
 and encode_efield f =

+ 14 - 0
src/typing/typeloadModule.ml

@@ -172,6 +172,19 @@ module ModuleLevel = struct
 					let priv = List.mem AbPrivate d.d_flags in
 					let path = make_path name priv d.d_meta p in
 					let p_enum_meta = Meta.maybe_get_pos Meta.Enum d.d_meta in
+					let a_default = try
+						begin match Meta.get Meta.DefaultValue d.d_meta with
+						| (_,[e],_) ->
+							Some (Lazy.from_fun (fun () ->
+								let ctx = TyperManager.clone_for_expr ctx_m FunStatic FunNotFunction in
+								type_expr ctx e WithType.value
+							))
+						| _ ->
+							raise Not_found
+						end
+					with Not_found ->
+						None
+					in
 					let a = {
 						a_path = path;
 						a_private = priv;
@@ -198,6 +211,7 @@ module ModuleLevel = struct
 						a_constructor = None;
 						a_extern = List.mem AbExtern d.d_flags;
 						a_enum = List.mem AbEnum d.d_flags || p_enum_meta <> None;
+						a_default;
 					} in
 					begin match p_enum_meta with
 						| None when a.a_enum -> a.a_meta <- (Meta.Enum,[],null_pos) :: a.a_meta; (* HAXE5: remove *)

+ 3 - 0
std/StdTypes.hx

@@ -43,6 +43,7 @@
 	@see https://haxe.org/manual/types-basic-types.html
 	@see https://haxe.org/manual/types-nullability.html
 **/
+@:defaultValue(0.0)
 @:coreType @:notNull @:runtimeValue abstract Float {}
 
 /**
@@ -58,6 +59,7 @@
 	@see https://haxe.org/manual/std-math-integer-math.html
 	@see https://haxe.org/manual/types-nullability.html
 **/
+@:defaultValue(0)
 @:coreType @:notNull @:runtimeValue abstract Int to Float {}
 
 #if (java || hl || cpp)
@@ -91,6 +93,7 @@ abstract Null<T> from T to T {}
 	@see https://haxe.org/manual/types-bool.html
 	@see https://haxe.org/manual/types-nullability.html
 **/
+@:defaultValue(false)
 @:coreType @:notNull @:runtimeValue abstract Bool {}
 
 /**

+ 1 - 1
std/cpp/Char.hx

@@ -22,4 +22,4 @@
 
 package cpp;
 
-@:coreType @:notNull @:runtimeValue abstract Char from Int to Int {}
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract Char from Int to Int {}

+ 1 - 1
std/cpp/Int16.hx

@@ -22,4 +22,4 @@
 
 package cpp;
 
-@:coreType @:notNull @:runtimeValue abstract Int16 from Int to Int {}
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract Int16 from Int to Int {}

+ 1 - 1
std/cpp/Int32.hx

@@ -22,4 +22,4 @@
 
 package cpp;
 
-@:coreType @:notNull @:runtimeValue abstract Int32 from Int to Int {}
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract Int32 from Int to Int {}

+ 1 - 0
std/cpp/Int64.hx

@@ -22,6 +22,7 @@
 
 package cpp;
 
+@:defaultValue(0)
 @:coreType @:notNull @:runtimeValue abstract Int64 from Int {
 
 	/**

+ 1 - 1
std/cpp/Int8.hx

@@ -22,4 +22,4 @@
 
 package cpp;
 
-@:coreType @:notNull @:runtimeValue abstract Int8 from Int to Int {}
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract Int8 from Int to Int {}

+ 1 - 1
std/cpp/SizeT.hx

@@ -23,5 +23,5 @@
 package cpp;
 
 @:native("size_t")
-@:scalar @:coreType @:notNull
+@:scalar @:coreType @:notNull @:defaultValue(0)
 extern abstract SizeT from(Int) to(Int) {}

+ 1 - 1
std/cpp/UInt16.hx

@@ -22,4 +22,4 @@
 
 package cpp;
 
-@:coreType @:notNull @:runtimeValue abstract UInt16 from Int to Int {}
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract UInt16 from Int to Int {}

+ 1 - 1
std/cpp/UInt32.hx

@@ -22,4 +22,4 @@
 
 package cpp;
 
-@:coreType @:notNull @:runtimeValue abstract UInt32 from Int to Int {}
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract UInt32 from Int to Int {}

+ 1 - 1
std/cpp/UInt64.hx

@@ -22,7 +22,7 @@
 
 package cpp;
 
-@:coreType @:notNull @:runtimeValue abstract UInt64 from Int {
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract UInt64 from Int {
 
 	/**
 		Destructively cast to Int

+ 1 - 1
std/cpp/UInt8.hx

@@ -22,4 +22,4 @@
 
 package cpp;
 
-@:coreType @:notNull @:runtimeValue abstract UInt8 from Int to Int {}
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract UInt8 from Int to Int {}

+ 5 - 0
std/haxe/macro/Type.hx

@@ -548,6 +548,11 @@ typedef AbstractType = BaseType & {
 		The method used for resolving unknown field access, if available.
 	**/
 	var resolveWrite:Null<ClassField>;
+
+	/**
+		The expression given as a default value for this abstract, if available.
+	**/
+	var defaultValue:Null<Ref<TypedExpr>>;
 }
 
 /**

+ 2 - 1
std/hl/I64.hx

@@ -22,7 +22,8 @@
 
 package hl;
 
-@:coreType @:notNull @:runtimeValue abstract I64 from Int {
+@:defaultValue(0)
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract I64 from Int {
 
 	/**
 		Destructively cast to Int

+ 1 - 1
std/hl/UI16.hx

@@ -22,4 +22,4 @@
 
 package hl;
 
-@:coreType @:notNull @:runtimeValue abstract UI16 to Int from Int {}
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract UI16 to Int from Int {}

+ 1 - 1
std/hl/UI8.hx

@@ -22,4 +22,4 @@
 
 package hl;
 
-@:coreType @:notNull @:runtimeValue abstract UI8 to Int from Int {}
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract UI8 to Int from Int {}

+ 1 - 1
std/jvm/Char16.hx

@@ -1,3 +1,3 @@
 package jvm;
 
-@:notNull @:runtimeValue @:coreType extern abstract Char16 from Int {}
+@:notNull @:runtimeValue @:coreType @:defaultValue(0) extern abstract Char16 from Int {}

+ 1 - 1
std/jvm/Int16.hx

@@ -1,3 +1,3 @@
 package jvm;
 
-@:notNull @:runtimeValue @:coreType extern abstract Int16 from Int {}
+@:notNull @:runtimeValue @:coreType @:defaultValue(0) extern abstract Int16 from Int {}

+ 1 - 0
std/jvm/Int64.hx

@@ -1,5 +1,6 @@
 package jvm;
 
+@:defaultValue(0)
 @:notNull @:runtimeValue @:coreType extern abstract Int64 from Int from Float {
 	@:op(A + B) public static function addI(lhs:Int64, rhs:Int):Int64;
 

+ 1 - 1
std/jvm/Int8.hx

@@ -1,3 +1,3 @@
 package jvm;
 
-@:notNull @:runtimeValue @:coreType extern abstract Int8 from Int {}
+@:notNull @:runtimeValue @:coreType @:defaultValue(0) extern abstract Int8 from Int {}