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 #7838
Comments
I don't think I want to mess with |
Ok, I've mentioned |
I don't want to change |
As long as it works only in the final-to-null way I don't see a problem. |
This is the diff of the tests that changed: Simn@a534053 So this change would allow:
|
I'm going through all occurrences of type.mllet is_physical_var_field f =
match f.cf_kind with
| Var { v_read = AccNormal | AccInline | AccNo } | Var { v_write = AccNormal | AccNo } -> true Technically, somebody could call this for TAnons as well, but it only makes sense for class fields where the distinction is correct. Should be fine fields.ml | Var v ->
match (match mode with MGet | MCall -> v.v_read | MSet -> v.v_write) with
| AccNo when not (Meta.has Meta.PrivateAccess ctx.meta) -> This means that | (MGet | MCall), Var {v_read = AccNever} ->
AKNo f.cf_name This is in the context of abstracts. nullSafety.mllet should_be_initialized field =
match field.cf_kind with
| Var { v_read = AccNormal | AccInline | AccNo } | Var { v_write = AccNormal | AccNo } -> true This is again in the context of class fields, so the distinction is good. initFunction.mlif v.v_write <> AccNever && not (Meta.has Meta.CoreApi cl.cl_meta) then com.warning "@:readOnly variable declared without `never` setter modifier" cf.cf_pos; This shows up in a function named gencpp.mllet is_readable class_def field =
(match field.cf_kind with
| Var { v_read = AccNever } when not (is_physical_field field) -> false let is_writable class_def field =
(match field.cf_kind with
| Var { v_write = AccNever } when not (is_physical_field field) -> false There's a match field.cf_kind, follow field.cf_type with
| Var { v_read = AccInline; v_write = AccNever },_ ->
script#writeOpLine IaInline; This matches the specific combination of inline-access where genphp7.mllet is_inline_var (field:tclass_field) =
match field.cf_kind with
| Var { v_read = AccInline; v_write = AccNever } -> true See above. optimizerTexpr.ml | FInstance (c,_,cf) | FStatic (c,cf) | FClosure (Some(c,_),cf) ->
begin match cf.cf_kind with
| Method MethDynamic -> false
| Method _ -> true
| Var {v_write = AccNever} when not c.cl_interface -> true This is again within the context of a class/interface ( matcher.ml | TField(_,FStatic(c,({cf_kind = Var {v_write = AccNever}} as cf))) ->
PatConstructor(con_static c cf e.epos,[]) Class context (due to typeloadFields.mlif (set = AccNormal && get = AccCall) || (set = AccNever && get = AccNever) then error (name ^ ": Unsupported property combination") p; This is in class context. -- Summary: Looks like we're good. |
* [typer] infer structure write as `never` instead of `null` see #7838 * [typer] allow assigning final fields to abtract null/never fields * [analyzer] fix `untyped global.field` read-only status * adjust tests * [typer] don't forget about final invariance in type_eq
Not touching this again for 4.0. We have to rethink this later. |
Following up on #7818:
This is weird. One could argue that unifying
never
withnull
creates a type hole: once access isnull
, you can use@:privateAccess
to read/write the value. You can even start withfinal
, promote tonever
, promote tonull
and mutate via@:privateAccess
. One "solution" would be to disallownever
to unify withnull
but it'd break a lot of existing code and make things more awkward than they already are.I would propose that:
null
andnever
get treated as being the same for structures/interfaces andfinal
may unify with both. Code written against read-only structures/interfaces should be able to operate on immutable objects (just not the other way around).@:privateAccess
cannot accessnull
on structures/interfaces, only on classes. Reasons:it closes the "type hole"
I'm relatively optimistic that very little code actually uses
@:privateAccess
on structures/interfacesit actually makes sense to only allow bypassing access restrictions on concrete implementations, because on structures/interfaces it can go absolutely wrong:
The text was updated successfully, but these errors were encountered: