|
@@ -535,23 +535,48 @@ and handle_efield ctx e p0 mode with_type =
|
|
|
in
|
|
|
|
|
|
(* loop through the given EField expression to figure out whether it's a dot-path that we have to resolve,
|
|
|
- or a simple field access chain *)
|
|
|
+ or a field access chain *)
|
|
|
let rec loop dot_path_acc (e,p) =
|
|
|
match e with
|
|
|
- | EField (e,s,efk) ->
|
|
|
+ | EField (e,s,EFNormal) ->
|
|
|
(* field access - accumulate and check further *)
|
|
|
- loop ((mk_dot_path_part s efk p) :: dot_path_acc) e
|
|
|
+ loop ((mk_dot_path_part s p) :: dot_path_acc) e
|
|
|
| EConst (Ident i) ->
|
|
|
(* it's a dot-path, so it might be either fully-qualified access (pack.Class.field)
|
|
|
or normal field access of a local/global/field identifier, proceed figuring this out *)
|
|
|
- dot_path (mk_dot_path_part i EFNormal p) dot_path_acc
|
|
|
+ dot_path (mk_dot_path_part i p) dot_path_acc mode with_type
|
|
|
+ | EField ((eobj,pobj),s,EFSafe) ->
|
|
|
+ (* safe navigation field access - definitely NOT a fully-qualified access,
|
|
|
+ create safe navigation chain from the object expression *)
|
|
|
+ let acc_obj = type_access ctx eobj pobj MGet WithType.value in
|
|
|
+ let eobj = acc_get ctx acc_obj pobj in
|
|
|
+ let eobj, tempvar = match (Texpr.skip eobj).eexpr with
|
|
|
+ | TLocal _ | TTypeExpr _ | TConst _ ->
|
|
|
+ eobj, None
|
|
|
+ | _ ->
|
|
|
+ let v = alloc_var VGenerated "tmp" eobj.etype eobj.epos in
|
|
|
+ let temp_var = mk (TVar(v, Some eobj)) ctx.t.tvoid v.v_pos in
|
|
|
+ let eobj = mk (TLocal v) v.v_type v.v_pos in
|
|
|
+ eobj, Some temp_var
|
|
|
+ in
|
|
|
+ let access = field_chain ctx ((mk_dot_path_part s p) :: dot_path_acc) (AKExpr eobj) mode with_type in
|
|
|
+ AKSafeNav {
|
|
|
+ sn_pos = p;
|
|
|
+ sn_base = eobj;
|
|
|
+ sn_temp_var = tempvar;
|
|
|
+ sn_access = access;
|
|
|
+ }
|
|
|
| _ ->
|
|
|
(* non-ident expr occured: definitely NOT a fully-qualified access,
|
|
|
resolve the field chain against this expression *)
|
|
|
- let e = type_access ctx e p MGet WithType.value in
|
|
|
- field_chain ctx dot_path_acc e
|
|
|
+ (match (type_access ctx e p MGet WithType.value) with
|
|
|
+ | AKSafeNav sn ->
|
|
|
+ (* further field access continues the safe navigation chain (after a non-field access inside the chain) *)
|
|
|
+ AKSafeNav { sn with sn_access = field_chain ctx dot_path_acc sn.sn_access mode with_type }
|
|
|
+ | e ->
|
|
|
+ field_chain ctx dot_path_acc e mode with_type)
|
|
|
in
|
|
|
- loop [] (e,p0) mode with_type
|
|
|
+ loop [] (e,p0)
|
|
|
|
|
|
and type_access ctx e p mode with_type =
|
|
|
match e with
|
|
@@ -598,15 +623,25 @@ and type_access ctx e p mode with_type =
|
|
|
handle_efield ctx e p mode with_type
|
|
|
| EArray (e1,e2) ->
|
|
|
type_array_access ctx e1 e2 p mode
|
|
|
+ | ECall (e, el) ->
|
|
|
+ type_call_access ctx e el mode with_type None p
|
|
|
| EDisplay (e,dk) ->
|
|
|
AKExpr (TyperDisplay.handle_edisplay ctx e dk mode with_type)
|
|
|
| _ ->
|
|
|
AKExpr (type_expr ~mode ctx (e,p) with_type)
|
|
|
|
|
|
and type_array_access ctx e1 e2 p mode =
|
|
|
- let e1 = type_expr ctx e1 WithType.value in
|
|
|
+ let e1, p1 = e1 in
|
|
|
+ let a1 = type_access ctx e1 p1 MGet WithType.value in
|
|
|
let e2 = type_expr ctx e2 WithType.value in
|
|
|
- Calls.array_access ctx e1 e2 mode p
|
|
|
+ match a1 with
|
|
|
+ | AKSafeNav sn ->
|
|
|
+ (* pack the array access inside the safe navigation chain *)
|
|
|
+ let e1 = acc_get ctx sn.sn_access sn.sn_pos in
|
|
|
+ AKSafeNav { sn with sn_access = Calls.array_access ctx e1 e2 mode p }
|
|
|
+ | _ ->
|
|
|
+ let e1 = acc_get ctx a1 p1 in
|
|
|
+ Calls.array_access ctx e1 e2 mode p
|
|
|
|
|
|
and type_vars ctx vl p =
|
|
|
let vl = List.map (fun ev ->
|
|
@@ -1598,7 +1633,7 @@ and type_meta ?(mode=MGet) ctx m e1 with_type p =
|
|
|
| (Meta.Inline,_,pinline) ->
|
|
|
begin match fst e1 with
|
|
|
| ECall(e1,el) ->
|
|
|
- type_call ctx e1 el WithType.value (Some pinline) p
|
|
|
+ acc_get ctx (type_call_access ctx e1 el MGet WithType.value (Some pinline) p) p
|
|
|
| ENew (t,el) ->
|
|
|
let e = type_new ctx t el with_type true p in
|
|
|
{e with eexpr = TMeta((Meta.Inline,[],null_pos),e)}
|
|
@@ -1625,34 +1660,32 @@ and type_call_target ctx e el with_type p_inline =
|
|
|
match p_inline with
|
|
|
| None ->
|
|
|
e
|
|
|
- | Some pinline -> match e with
|
|
|
- | AKField fa ->
|
|
|
- check_inline fa.fa_field pinline;
|
|
|
- AKField({fa with fa_inline = true})
|
|
|
- | AKUsingField sea ->
|
|
|
- check_inline sea.se_access.fa_field pinline;
|
|
|
- AKUsingField {sea with se_access = {sea.se_access with fa_inline = true}}
|
|
|
- | AKExpr {eexpr = TLocal _} ->
|
|
|
- display_error ctx.com "Cannot force inline on local functions" pinline;
|
|
|
- e
|
|
|
- | _ ->
|
|
|
- e
|
|
|
+ | Some pinline ->
|
|
|
+ let rec loop e =
|
|
|
+ match e with
|
|
|
+ | AKSafeNav sn ->
|
|
|
+ AKSafeNav { sn with sn_access = loop sn.sn_access }
|
|
|
+ | AKField fa ->
|
|
|
+ check_inline fa.fa_field pinline;
|
|
|
+ AKField({fa with fa_inline = true})
|
|
|
+ | AKUsingField sea ->
|
|
|
+ check_inline sea.se_access.fa_field pinline;
|
|
|
+ AKUsingField {sea with se_access = {sea.se_access with fa_inline = true}}
|
|
|
+ | AKExpr {eexpr = TLocal _} ->
|
|
|
+ display_error ctx.com "Cannot force inline on local functions" pinline;
|
|
|
+ e
|
|
|
+ | _ ->
|
|
|
+ e
|
|
|
+ in
|
|
|
+ loop e
|
|
|
|
|
|
-and type_call ?(mode=MGet) ctx e el (with_type:WithType.t) p_inline p =
|
|
|
+and type_call_access ctx e el mode with_type p_inline p =
|
|
|
try
|
|
|
- type_call_builtin ctx e el mode with_type p
|
|
|
+ let e = type_call_builtin ctx e el mode with_type p in
|
|
|
+ AKExpr e
|
|
|
with Exit ->
|
|
|
let acc = type_call_target ctx e el with_type p_inline in
|
|
|
- let e = build_call ~mode ctx acc el with_type p in
|
|
|
- check_dynamic_super_method_call ctx e;
|
|
|
- e
|
|
|
-
|
|
|
-and check_dynamic_super_method_call ctx e =
|
|
|
- match e.eexpr with
|
|
|
- | TCall ({ eexpr = TField ({ eexpr = TConst TSuper }, FInstance(_, _, { cf_kind = Method MethDynamic; cf_name = name })); epos = p }, _) ->
|
|
|
- ctx.com.error ("Cannot call super." ^ name ^ " since it's a dynamic method") p
|
|
|
- | _ ->
|
|
|
- ()
|
|
|
+ build_call_access ctx acc el mode with_type p
|
|
|
|
|
|
and type_call_builtin ctx e el mode with_type p =
|
|
|
match e, el with
|
|
@@ -1750,7 +1783,8 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
|
|
|
let e = maybe_type_against_enum ctx (fun () -> type_ident ctx s p mode with_type) with_type false p in
|
|
|
acc_get ctx e p
|
|
|
| EField _
|
|
|
- | EArray _ ->
|
|
|
+ | EArray _
|
|
|
+ | ECall _ ->
|
|
|
acc_get ctx (type_access ctx e p mode with_type) p
|
|
|
| EConst (Regexp (r,opt)) ->
|
|
|
let str = mk (TConst (TString r)) ctx.t.tstring p in
|
|
@@ -1902,8 +1936,6 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
|
|
|
| EThrow e ->
|
|
|
let e = type_expr ctx e WithType.value in
|
|
|
mk (TThrow e) (spawn_monomorph ctx p) p
|
|
|
- | ECall (e,el) ->
|
|
|
- type_call ~mode ctx e el with_type None p
|
|
|
| ENew (t,el) ->
|
|
|
type_new ctx t el with_type false p
|
|
|
| EUnop (op,flag,e) ->
|