Skip to content

Commit dbef951

Browse files
committed
Allow redefinition of non-physical vars
1 parent 57b27b4 commit dbef951

6 files changed

Lines changed: 182 additions & 1 deletion

File tree

src/typing/typeloadFields.ml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,35 @@ module TypeBinding = struct
733733
if not fctx.is_static && not cctx.is_lib then begin match get_declared cf.cf_name c.cl_super with
734734
| None -> ()
735735
| Some (csup,_) ->
736-
display_error ctx.com ("Redefinition of variable " ^ cf.cf_name ^ " in subclass is not allowed. Previously declared at " ^ (s_type_path csup.cl_path) ) cf.cf_name_pos
736+
let error_redefinition () =
737+
display_error ctx.com ("Redefinition of variable " ^ cf.cf_name ^ " in subclass is not allowed. Previously declared at " ^ (s_type_path csup.cl_path)) cf.cf_name_pos
738+
in
739+
(try
740+
let cf_parent = PMap.find cf.cf_name csup.cl_fields in
741+
if (
742+
has_class_field_flag cf_parent CfPublic
743+
&& not (has_class_field_flag cf CfPublic)
744+
) then
745+
display_error ctx.com ("Variable " ^ cf.cf_name ^ " has less visibility (public/private) than superclass one") cf.cf_pos
746+
else if is_physical_var_field cf_parent then
747+
error_redefinition ()
748+
else begin
749+
let is_narrowing parent_acc child_acc = match parent_acc, child_acc with
750+
| AccCall, (AccPrivateCall | AccNever) -> true
751+
| AccPrivateCall, AccNever -> true
752+
| _ -> false
753+
in
754+
match cf.cf_kind, cf_parent.cf_kind with
755+
| Var child_v, Var parent_v ->
756+
if is_narrowing parent_v.v_read child_v.v_read then
757+
display_error ctx.com ("Cannot narrow read access of " ^ cf.cf_name ^ " in subclass") cf.cf_name_pos
758+
else if is_narrowing parent_v.v_write child_v.v_write then
759+
display_error ctx.com ("Cannot narrow write access of " ^ cf.cf_name ^ " in subclass") cf.cf_name_pos
760+
| _ ->
761+
error_redefinition ()
762+
end
763+
with Not_found ->
764+
error_redefinition ())
737765
end
738766

739767
let bind_var_expression ctx_f cctx fctx cf e =
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
class PhysicalParent {
2+
public var x:Int;
3+
public function new() {}
4+
}
5+
6+
class PhysicalPropertyParent {
7+
@:isVar public var x(get, set):Int;
8+
public function new() {}
9+
function get_x() return x;
10+
function set_x(v) return x = v;
11+
}
12+
13+
class RedefinePhysical extends PhysicalParent {
14+
public var x:Int;
15+
}
16+
17+
class RedefinePhysicalProperty extends PhysicalPropertyParent {
18+
@:isVar public var x(get, set):Int;
19+
}
20+
21+
class RedefinePhysicalPropAsProperty extends PhysicalPropertyParent {
22+
public var x(get, set):Int;
23+
}
24+
25+
class RedefinePhysicalAsProperty extends PhysicalParent {
26+
public var x(get, set):Int;
27+
function get_x() return 0;
28+
function set_x(v) return v;
29+
}
30+
31+
class NonPhysicalParent {
32+
public var x(get, set):Int;
33+
public function new() {}
34+
function get_x() return 0;
35+
function set_x(v) return v;
36+
}
37+
38+
class NarrowRead extends NonPhysicalParent {
39+
public var x(never, set):Int;
40+
}
41+
42+
class NarrowWrite extends NonPhysicalParent {
43+
public var x(get, never):Int;
44+
}
45+
46+
class NarrowWrite2 extends NonPhysicalParent {
47+
public var x(get, private set):Int;
48+
}
49+
50+
class PrivateVar extends NonPhysicalParent {
51+
var x(get, set):Int;
52+
}
53+
54+
function main() {}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-main Main
2+
--interp
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Main.hx:51: characters 2-22 : Variable x has less visibility (public/private) than superclass one
2+
Main.hx:47: characters 13-14 : Cannot narrow write access of x in subclass
3+
Main.hx:43: characters 13-14 : Cannot narrow write access of x in subclass
4+
Main.hx:39: characters 13-14 : Cannot narrow read access of x in subclass
5+
Main.hx:26: characters 13-14 : Redefinition of variable x in subclass is not allowed. Previously declared at PhysicalParent
6+
Main.hx:22: characters 13-14 : Redefinition of variable x in subclass is not allowed. Previously declared at PhysicalPropertyParent
7+
Main.hx:18: characters 21-22 : Redefinition of variable x in subclass is not allowed. Previously declared at PhysicalPropertyParent
8+
Main.hx:14: characters 13-14 : Redefinition of variable x in subclass is not allowed. Previously declared at PhysicalParent

tests/unit/src/unit/TestMain.hx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ function main() {
106106
#if (!flash && !hl && !cppia)
107107
new TestCoroutines(),
108108
#end
109+
new TestRedefinition(),
109110
// new TestUnspecified(),
110111
];
111112

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package unit;
2+
3+
abstract class Dispatcher {
4+
public var scheduler(get, never):Float;
5+
6+
abstract function get_scheduler():Float;
7+
}
8+
9+
class ConcreteDispatcher extends Dispatcher {
10+
@:isVar public var scheduler(get, null):Int;
11+
12+
public function new(v:Int) {
13+
this.scheduler = v;
14+
}
15+
16+
function get_scheduler() {
17+
return scheduler;
18+
}
19+
}
20+
21+
class ParentWithNonPhysical {
22+
public function new() {}
23+
24+
public var name(get, private set):String;
25+
26+
function get_name():String
27+
return "parent";
28+
29+
function set_name(v:String):String
30+
return "parent";
31+
}
32+
33+
class ChildWidened extends ParentWithNonPhysical {
34+
@:isVar public var name(get, set):String;
35+
36+
public function new(v:String) {
37+
super();
38+
this.name = v;
39+
}
40+
41+
override function get_name():String
42+
return name;
43+
44+
override function set_name(v:String):String
45+
return name = v;
46+
}
47+
48+
class ChildWidenedNonPhysical extends ParentWithNonPhysical {
49+
public var name(get, set):String;
50+
51+
public function new() {
52+
super();
53+
}
54+
55+
override function get_name():String
56+
return "child";
57+
58+
override function set_name(v:String):String
59+
return v;
60+
}
61+
62+
class TestRedefinition extends Test {
63+
public function testDispatcher() {
64+
final dispatcher = new ConcreteDispatcher(123);
65+
eq(dispatcher.scheduler, 123);
66+
final generalDispatcher:Dispatcher = dispatcher;
67+
eq(generalDispatcher.scheduler, 123.0);
68+
}
69+
70+
public function testWidening() {
71+
final child = new ChildWidened("child");
72+
eq(child.name, "child");
73+
child.name = "new child";
74+
eq(child.name, "new child");
75+
76+
final parent:ParentWithNonPhysical = child;
77+
eq(parent.name, "new child");
78+
}
79+
80+
public function testWideningNonPhysical() {
81+
final child = new ChildWidenedNonPhysical();
82+
eq(child.name, "child");
83+
child.name = "new child";
84+
85+
final parent:ParentWithNonPhysical = child;
86+
eq(parent.name, "child");
87+
}
88+
}

0 commit comments

Comments
 (0)