Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Final vs. never vs. null #8011

Merged
merged 7 commits into from Mar 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/core/type.ml
Expand Up @@ -1905,6 +1905,7 @@ let rec type_eq param a b =
try
let f2 = PMap.find n a2.a_fields in
if f1.cf_kind <> f2.cf_kind && (param = EqStrict || param = EqCoreType || not (unify_kind f1.cf_kind f2.cf_kind)) then error [invalid_kind n f1.cf_kind f2.cf_kind];
if has_class_field_flag f1 CfFinal <> has_class_field_flag f2 CfFinal then raise (Unify_error [FinalInvariance]);
let a = f1.cf_type and b = f2.cf_type in
(try type_eq param a b with Unify_error l -> error (invalid_field n :: l));
if (has_class_field_flag f1 CfPublic) != (has_class_field_flag f2 CfPublic) then error [invalid_visibility n];
Expand Down Expand Up @@ -2245,7 +2246,7 @@ and unify_anons a b a1 a2 =
let f1 = PMap.find n a1.a_fields in
if not (unify_kind f1.cf_kind f2.cf_kind) then
(match !(a1.a_status), f1.cf_kind, f2.cf_kind with
| Opened, Var { v_read = AccNormal; v_write = AccNo }, Var { v_read = AccNormal; v_write = AccNormal } ->
| Opened, Var { v_read = AccNormal; v_write = AccNever }, Var { v_read = AccNormal; v_write = AccNormal } ->
f1.cf_kind <- f2.cf_kind;
| _ -> error [invalid_kind n f1.cf_kind f2.cf_kind]);
if (has_class_field_flag f2 CfPublic) && not (has_class_field_flag f1 CfPublic) then error [invalid_visibility n];
Expand Down Expand Up @@ -2397,7 +2398,15 @@ and unify_with_access f1 t1 f2 =
| Var { v_read = AccNo } | Var { v_read = AccNever } -> unify f2.cf_type t1
(* read only *)
| Method MethNormal | Method MethInline | Var { v_write = AccNo } | Var { v_write = AccNever } ->
if (has_class_field_flag f1 CfFinal) <> (has_class_field_flag f2 CfFinal) then raise (Unify_error [FinalInvariance]);
begin match (has_class_field_flag f1 CfFinal),(has_class_field_flag f2 CfFinal) with
| true,true
| false,false ->
()
| true,false ->
()
| false,true ->
raise (Unify_error [FinalInvariance]);
end;
unify t1 f2.cf_type
(* read/write *)
| _ -> with_variance (type_eq EqBothDynamic) t1 f2.cf_type
Expand Down
2 changes: 1 addition & 1 deletion src/optimization/optimizerTexpr.ml
Expand Up @@ -31,7 +31,7 @@ let is_read_only_field_access e fa = match fa with
true
| FDynamic _ ->
false
| FAnon {cf_kind = Var {v_write = AccNo}} when (match e.eexpr with TIdent _ -> true | _ -> false) -> true
| FAnon {cf_kind = Var {v_write = AccNo | AccNever}} when (match e.eexpr with TIdent _ -> true | _ -> false) -> true
| FInstance (c,_,cf) | FStatic (c,cf) | FClosure (Some(c,_),cf) ->
begin match cf.cf_kind with
| Method MethDynamic -> false
Expand Down
2 changes: 1 addition & 1 deletion src/typing/fields.ml
Expand Up @@ -461,7 +461,7 @@ let rec type_field ?(resume=false) ctx e i p mode =
| TMono r ->
let f = {
(mk_field i (mk_mono()) p null_pos) with
cf_kind = Var { v_read = AccNormal; v_write = (match mode with MSet -> AccNormal | MGet | MCall -> AccNo) };
cf_kind = Var { v_read = AccNormal; v_write = (match mode with MSet -> AccNormal | MGet | MCall -> AccNever) };
} in
let x = ref Opened in
let t = TAnon { a_fields = PMap.add i f PMap.empty; a_status = x } in
Expand Down
8 changes: 4 additions & 4 deletions tests/unit/src/unit/TestFieldVariance.hx
Expand Up @@ -85,7 +85,7 @@ class TestFieldVariance extends Test {
// anon to final anon

t(typeError(finalField = publicField));
finalField = neverField;
t(typeError(finalField = neverField));
t(typeError(finalField = nullField));

// anon to never anon
Expand All @@ -97,7 +97,7 @@ class TestFieldVariance extends Test {
// anon to null anon

nullField = publicField;
t(typeError(nullField = finalField));
nullField = finalField;
nullField = neverField;

// class to final anon
Expand All @@ -110,14 +110,14 @@ class TestFieldVariance extends Test {
// class to never anon

neverField = publicFieldClass;
t(typeError(neverField = finalFieldClass));
neverField = finalFieldClass;
neverField = neverFieldClass;
neverField = nullFieldClass;

// class to null anon

nullField = publicFieldClass;
t(typeError(nullField = finalFieldClass));
nullField = finalFieldClass;
nullField = neverFieldClass;
nullField = nullFieldClass;
}
Expand Down