Quellcode durchsuchen

[java/cs] Added support for @:readOnly fields when eagerly initialized. Closes #2061

Cauê Waneck vor 10 Jahren
Ursprung
Commit
ef5f4b4562

+ 22 - 1
gencommon.ml

@@ -2016,7 +2016,18 @@ struct
 
 		let priority = solve_deps name [DBefore OverloadingConstructor.priority]
 
-		let configure gen should_handle_dynamic_functions =
+		let ensure_simple_expr gen e =
+			let rec iter e = match e.eexpr with
+				| TConst _ | TLocal _ | TArray _ | TBinop _
+				| TField _ | TTypeExpr _ | TParenthesis _
+				| TCall _ | TNew _ | TUnop _ ->
+					Type.iter iter e
+				| _ ->
+					gen.gcon.error "Expression is too complex for a readonly variable initialization" e.epos
+			in
+			iter e
+
+		let configure gen should_handle_dynamic_functions readonly_support =
 			let handle_override_dynfun acc e this field =
 				let add_expr = ref None in
 				let v = mk_temp gen ("super_" ^ field) e.etype in
@@ -2050,6 +2061,11 @@ struct
 				in
 				let init = List.fold_left (fun acc cf ->
 					match cf.cf_kind, should_handle_dynamic_functions with
+						| (Var v, _) when Meta.has Meta.ReadOnly cf.cf_meta && readonly_support ->
+								if v.v_write <> AccNever then gen.gcon.warning "@:readOnly variable declared without `never` setter modifier" cf.cf_pos;
+								(match cf.cf_expr with
+									| None -> gen.gcon.warning "Uninitialized readonly variable" cf.cf_pos; acc
+									| Some e -> ensure_simple_expr gen e; acc)
 						| (Var _, _)
 						| (Method (MethDynamic), true) when not (Type.is_extern_field cf) ->
 							(match cf.cf_expr with
@@ -2086,6 +2102,11 @@ struct
 				if should_handle_dynamic_functions then begin
 					let funs = List.fold_left (fun acc cf ->
 						match cf.cf_kind with
+							| Var v when Meta.has Meta.ReadOnly cf.cf_meta && readonly_support ->
+									if v.v_write <> AccNever then gen.gcon.warning "@:readOnly variable declared without `never` setter modifier" cf.cf_pos;
+									(match cf.cf_expr with
+										| None -> acc
+										| Some e -> ensure_simple_expr gen e; acc)
 							| Var _
 							| Method(MethDynamic) ->
 								(match cf.cf_expr, cf.cf_params with

+ 1 - 1
gencs.ml

@@ -2627,7 +2627,7 @@ let configure gen =
 
 	ObjectDeclMap.configure gen (ObjectDeclMap.traverse gen objdecl_fn);
 
-	InitFunction.configure gen true;
+	InitFunction.configure gen true true;
 	TArrayTransform.configure gen (TArrayTransform.default_implementation gen (
 	fun e binop ->
 		match e.eexpr with

+ 2 - 2
genjava.ml

@@ -770,7 +770,7 @@ let rec get_fun_modifiers meta access modifiers =
 		| [] -> access,modifiers
 		| (Meta.Protected,[],_) :: meta -> get_fun_modifiers meta "protected" modifiers
 		| (Meta.Internal,[],_) :: meta -> get_fun_modifiers meta "" modifiers
-		(*| (Meta.ReadOnly,[],_) :: meta -> get_fun_modifiers meta access ("readonly" :: modifiers)*)
+		| (Meta.ReadOnly,[],_) :: meta -> get_fun_modifiers meta access ("final" :: modifiers)
 		(*| (Meta.Unsafe,[],_) :: meta -> get_fun_modifiers meta access ("unsafe" :: modifiers)*)
 		| (Meta.Volatile,[],_) :: meta -> get_fun_modifiers meta access ("volatile" :: modifiers)
 		| (Meta.Transient,[],_) :: meta -> get_fun_modifiers meta access ("transient" :: modifiers)
@@ -2043,7 +2043,7 @@ let configure gen =
 
 	ObjectDeclMap.configure gen (ObjectDeclMap.traverse gen objdecl_fn);
 
-	InitFunction.configure gen true;
+	InitFunction.configure gen true true;
 	TArrayTransform.configure gen (TArrayTransform.default_implementation gen (
 	fun e _ ->
 		match e.eexpr with

+ 4 - 4
std/cs/internal/HxObject.hx

@@ -74,13 +74,13 @@ private class DynamicObject extends HxObject implements Dynamic
 #end
 private class Enum
 {
-	@:readOnly private var index:Int;
-	@:readOnly private var params:Array<{}>;
+	@:readOnly private var index(default,never):Int;
+	@:readOnly private var params(default,never):Array<{}>;
 
 	public function new(index:Int, params:Array<{}>)
 	{
-		this.index = index;
-		this.params = params;
+		untyped this.index = index;
+		untyped this.params = params;
 	}
 	@:final public function getTag():String
 	{

+ 4 - 4
std/cs/internal/Null.hx

@@ -43,8 +43,8 @@ package cs.internal;
 @:keep @:struct @:nativeGen @:native("haxe.lang.Null") private class Nullable<T>
 {
 
-	@:readOnly public var value:T;
-	@:readOnly public var hasValue:Bool;
+	@:readOnly public var value(default,never):T;
+	@:readOnly public var hasValue(default,never):Bool;
 
 	@:functionCode('
 			if ( !(v is System.ValueType) && System.Object.ReferenceEquals(v, default(T)))
@@ -57,8 +57,8 @@ package cs.internal;
 	')
 	public function new(v:T, hasValue:Bool)
 	{
-		this.value = v;
-		this.hasValue = hasValue;
+		untyped this.value = v;
+		untyped this.hasValue = hasValue;
 	}
 
 	@:functionCode('

+ 4 - 4
std/java/internal/HxObject.hx

@@ -70,13 +70,13 @@ private class DynamicObject extends HxObject implements Dynamic
 @:keep
 private class Enum
 {
-	@:readOnly private var index:Int;
-	@:readOnly private var params:Array<{}>;
+	@:readOnly private var index(default,never):Int;
+	@:readOnly private var params(default,never):Array<{}>;
 
 	public function new(index:Int, params:Array<{}>)
 	{
-		this.index = index;
-		this.params = params;
+		untyped this.index = index;
+		untyped this.params = params;
 	}
 	@:final public function getTag():String
 	{

+ 33 - 0
tests/unit/src/unit/issues/Issue2061.hx

@@ -0,0 +1,33 @@
+package unit.issues;
+
+class Issue2061 extends Test
+{
+	function test()
+	{
+		eq("Hello",FinalTest.hello);
+		eq("World",FinalTest.world);
+		eq("Hello World",FinalTest.someValue);
+		var v = new FinalTest();
+		eq("Const Value", v.ctorValue);
+		eq("Hello World", v.ctorValue2);
+	}
+}
+
+class FinalTest
+{
+	@:readOnly public static var hello(default,never) = "Hello";
+	@:readOnly public static var world(default,never) = "World";
+	@:readOnly public static var someValue(default,never) = getSomeValue();
+
+	@:readOnly public var ctorValue(default,never) = "Const Value";
+	@:readOnly public var ctorValue2(default,never) = getSomeValue();
+
+	public function new()
+	{
+	}
+
+	private static function getSomeValue()
+	{
+		return hello + " " + world;
+	}
+}