瀏覽代碼

Rework `unify_field_call` (#9734)

* [typer] remove concrete type knowledge from `unify_field_call`

* [typer] don't forget about closure

* [typer] turn AKUsing data into a record

* [typer] lose `se_field_expr`

* [typer] make `unify_field_call` aware of static extensions

* [typer] reduce some data redundancy

* [typer] generalize AKInline into AKField

* [typer] make AKUsing use `field_access_mode`

* [typer] use custom ADT for FieldAccess mode

* [typer] add FAAbstract

* [typer] remove `unapply_fa`

* [typer] use FAAbstract for enum abstract values too

* [typer] AKSet -> AKSetter (just parity for now)

* [typer] absorb AKMacro too

* [typer] use `field_access_access` as argument to `unify_field_work`

* [typer] rename some things

* [typer] don't lose actual field type after call arg unification

* [typer] avoid some class field monomorph leakage

* [typer] use `unify_raise` if we want to catch something

* [typer] move abstract `this` handling from syntax to typing

closes #9739

* [typer] flatten `access_kind` structure

* [std] fex Victor

* [typer] remove concrete type from `field_access`

* [typer] calls on AKUsingGetter can happen

* [typer] align setter typing with getter typing

* [typer] generalize to allow multiple typed arguments

* [typer] separate concerns of `type_field` and `field_access`

* [typer] rename some things

* [typer] bring back special display mode case

* [typer] dig up actual class for visibility checks

* [typer] try to get dot path modes right

* [typer] remove rogue `check_field_access`

* [typer] hack around abstract self representation problems

* [typer] apply abstract `this` type rewrite

* [typer] redo AKFieldSet

* [typer] merge Setter/Getter into Accessor

* [typer] AKFieldSet -> AKResolve

* [typer] change accessor handling again

* [typer] clean up a bit

* [typer] allow missing accessors on externs

* [typer] relocate `resolve_accessor`

* [typer] rename

* [typer] that's not how unops work

* [typer] support AKResolve for unops

* [typer] that's still not how unops work

* [flash] shut up

* [typer] move abstract `this` logic to `unify_field_call`

* [typer] deal with property overrides
Simon Krajewski 5 年之前
父節點
當前提交
b6a8af0c28
共有 8 個文件被更改,包括 874 次插入654 次删除
  1. 11 0
      src/core/tOther.ml
  2. 322 259
      src/typing/calls.ml
  3. 121 202
      src/typing/fields.ml
  4. 221 156
      src/typing/typer.ml
  5. 179 15
      src/typing/typerBase.ml
  6. 18 21
      src/typing/typerDotPath.ml
  7. 1 1
      std/flash/Boot.hx
  8. 1 0
      tests/misc/projects/Issue5940/compile-fail.hxml.stderr

+ 11 - 0
src/core/tOther.ml

@@ -310,6 +310,17 @@ module TClass = struct
 			c.cl_fields <- PMap.add cf.cf_name cf c.cl_fields;
 			c.cl_ordered_fields <- cf :: c.cl_ordered_fields;
 		end
+
+	let get_map_function c tl =
+		let rec loop map c = match c.cl_super with
+			| Some(csup,tl) ->
+				let map t = map (apply_params csup.cl_params tl t) in
+				loop map csup
+			| None ->
+				map
+		in
+		let apply = apply_params c.cl_params tl in
+		loop apply c
 end
 
 let s_class_path c =

+ 322 - 259
src/typing/calls.ml

@@ -236,52 +236,62 @@ type overload_kind =
 	| OverloadMeta (* @:overload(function() {}) *)
 	| OverloadNone
 
-let unify_field_call ctx fa el args ret p inline =
-	let map_cf cf0 map cf =
-		let monos = Monomorph.spawn_constrained_monos map cf.cf_params in
-		let t = map (apply_params cf.cf_params monos cf.cf_type) in
-		t,cf
+let unify_field_call ctx fa el_typed el p inline =
+	let expand_overloads cf =
+		cf :: cf.cf_overloads
 	in
-	let expand_overloads map cf =
-		(TFun(args,ret),cf) :: (List.map (map_cf cf map) cf.cf_overloads)
-	in
-	let candidates,co,static,cf,mk_fa = match fa with
-		| FStatic(c,cf) ->
-			expand_overloads (fun t -> t) cf,Some c,true,cf,(fun cf -> FStatic(c,cf))
-		| FAnon cf ->
-			expand_overloads (fun t -> t) cf,None,false,cf,(fun cf -> FAnon cf)
-		| FInstance(c,tl,cf) ->
-			let map = apply_params c.cl_params tl in
+	let candidates,co,static,map,tmap = match fa.fa_host with
+		| FHStatic c ->
+			expand_overloads fa.fa_field,Some c,true,(fun t -> t),(fun t -> t)
+		| FHAnon ->
+			expand_overloads fa.fa_field,None,false,(fun t -> t),(fun t -> t)
+		| FHInstance(c,tl) ->
+			let cf = fa.fa_field in
 			let cfl = if cf.cf_name = "new" || not (has_class_field_flag cf CfOverload) then
-				(TFun(args,ret),cf) :: List.map (map_cf cf map) cf.cf_overloads
+				cf :: cf.cf_overloads
 			else
 				List.map (fun (t,cf) ->
-					let monos = Monomorph.spawn_constrained_monos map cf.cf_params in
-					map (apply_params cf.cf_params monos t),cf
+					cf
 				) (Overloads.get_overloads ctx.com c cf.cf_name)
 			in
-			cfl,Some c,false,cf,(fun cf -> FInstance(c,tl,cf))
-		| FClosure(co,cf) ->
-			let c = match co with None -> None | Some (c,_) -> Some c in
-			expand_overloads (fun t -> t) cf,c,false,cf,(fun cf -> match co with None -> FAnon cf | Some (c,tl) -> FInstance(c,tl,cf))
-		| _ ->
-			error "Invalid field call" p
+			cfl,Some c,false,TClass.get_map_function c tl,(fun t -> t)
+		| FHAbstract(a,tl,c) ->
+			let map = apply_params a.a_params tl in
+			expand_overloads fa.fa_field,Some c,true,map,(fun t -> map a.a_this)
 	in
-	let is_forced_inline = is_forced_inline co cf in
-	let overload_kind = if has_class_field_flag cf CfOverload then OverloadProper
-		else if cf.cf_overloads <> [] then OverloadMeta
+	let is_forced_inline = is_forced_inline co fa.fa_field in
+	let overload_kind = if has_class_field_flag fa.fa_field CfOverload then OverloadProper
+		else if fa.fa_field.cf_overloads <> [] then OverloadMeta
 		else OverloadNone
 	in
-	let attempt_call t cf = match follow t with
+	let attempt_call cf =
+		let monos = Monomorph.spawn_constrained_monos map cf.cf_params in
+		let t = map (apply_params cf.cf_params monos cf.cf_type) in
+		match follow t with
 		| TFun(args,ret) ->
+			let rec loop acc tmap args el_typed = match args,el_typed with
+				| (_,_,t0) :: args,e :: el_typed ->
+					begin try
+						unify_raise ctx (tmap e.etype) t0 e.epos;
+					with Error(Unify _ as msg,p) ->
+						let call_error = Call_error(Could_not_unify msg) in
+						raise(Error(call_error,p))
+					end;
+					loop (e :: acc) (fun t -> t) args el_typed
+				| _ ->
+					(fun el -> (List.rev acc) @ el),args
+			in
+			let get_call_args,args = loop [] tmap args el_typed in
 			let el,tf = unify_call_args' ctx el args ret p inline is_forced_inline in
-			let mk_call ethis p_field inline =
-				let ef = mk (TField(ethis,mk_fa cf)) t p_field in
-				make_call ctx ef (List.map fst el) ret ~force_inline:inline p
+			let mk_call () =
+				let ef = mk (TField(fa.fa_on,FieldAccess.apply_fa cf fa.fa_host)) t fa.fa_pos in
+				let el = List.map fst el in
+				let el = get_call_args el in
+				make_call ctx ef el ret ~force_inline:inline p
 			in
 			make_field_call_candidate el tf cf mk_call
-		| _ ->
-			die "" __LOC__
+		| t ->
+			error (s_type (print_context()) t ^ " cannot be called") p
 	in
 	let maybe_raise_unknown_ident cerr p =
 		let rec loop err =
@@ -295,12 +305,14 @@ let unify_field_call ctx fa el args ret p inline =
 	let attempt_calls candidates =
 		let rec loop candidates = match candidates with
 			| [] -> [],[]
-			| (t,cf) :: candidates ->
+			| cf :: candidates ->
 				let known_monos = List.map (fun (m,_) ->
 					m,m.tm_type,m.tm_constraints
 				) ctx.monomorphs.perfunction in
+				let current_monos = ctx.monomorphs.perfunction in
 				begin try
-					let candidate = attempt_call t cf in
+					let candidate = attempt_call cf in
+					ctx.monomorphs.perfunction <- current_monos;
 					if overload_kind = OverloadProper then begin
 						let candidates,failures = loop candidates in
 						candidate :: candidates,failures
@@ -308,9 +320,10 @@ let unify_field_call ctx fa el args ret p inline =
 						[candidate],[]
 				with Error ((Call_error cerr as err),p) ->
 					List.iter (fun (m,t,constr) ->
-						m.tm_type <- t;
-						m.tm_constraints <- constr;
+						if t != m.tm_type then m.tm_type <- t;
+						if constr != m.tm_constraints then m.tm_constraints <- constr;
 					) known_monos;
+					ctx.monomorphs.perfunction <- current_monos;
 					maybe_raise_unknown_ident cerr p;
 					let candidates,failures = loop candidates in
 					candidates,(cf,err,p) :: failures
@@ -319,12 +332,12 @@ let unify_field_call ctx fa el args ret p inline =
 		loop candidates
 	in
 	let fail_fun () =
-		let tf = TFun(args,ret) in
-		let call = (fun ethis p_field _ ->
-			let e1 = mk (TField(ethis,mk_fa cf)) tf p_field in
-			mk (TCall(e1,[])) ret p)
+		let tf = TFun(List.map (fun _ -> ("",false,t_dynamic)) el,t_dynamic) in
+		let call () =
+			let ef = mk (TField(fa.fa_on,FieldAccess.apply_fa fa.fa_field fa.fa_host)) tf fa.fa_pos in
+			mk (TCall(ef,[])) t_dynamic p
 		in
-		make_field_call_candidate [] tf cf call
+		make_field_call_candidate [] tf fa.fa_field call
 	in
 	let maybe_check_access cf =
 		(* type_field doesn't check access for overloads, so let's check it here *)
@@ -336,10 +349,10 @@ let unify_field_call ctx fa el args ret p inline =
 		end;
 	in
 	match candidates with
-	| [t,cf] ->
+	| [cf] ->
 		if overload_kind = OverloadProper then maybe_check_access cf;
 		begin try
-			attempt_call t cf
+			attempt_call cf
 		with Error _ when ctx.com.display.dms_error_policy = EPIgnore ->
 			fail_fun();
 		end
@@ -371,27 +384,24 @@ let unify_field_call ctx fa el args ret p inline =
 			| fcc :: _ -> fcc
 		end
 
-let type_generic_function ctx (e,fa) el ?(using_param=None) with_type p =
-	let c,tl,cf,stat = match fa with
-		| FInstance(c,tl,cf) -> c,tl,cf,false
-		| FStatic(c,cf) -> c,[],cf,true
+let type_generic_function ctx fa el_typed el with_type p =
+	let c,tl,stat = match fa.fa_host with
+		| FHInstance(c,tl) -> c,tl,false
+		| FHStatic c -> c,[],true
 		| _ -> die "" __LOC__
 	in
+	let cf = fa.fa_field in
 	if cf.cf_params = [] then error "Function has no type parameters and cannot be generic" p;
 	let map = if stat then (fun t -> t) else apply_params c.cl_params tl in
 	let monos = Monomorph.spawn_constrained_monos map cf.cf_params in
 	let map_monos t = apply_params cf.cf_params monos t in
 	let map t = if stat then map_monos t else apply_params c.cl_params tl (map_monos t) in
 	let t = map cf.cf_type in
-	let args,ret = match t,using_param with
-		| TFun((_,_,ta) :: args,ret),Some e ->
-			let ta = if not (Meta.has Meta.Impl cf.cf_meta) then ta
-			else match follow ta with TAbstract(a,tl) -> Abstract.get_underlying_type a tl | _ -> die "" __LOC__
-			in
-			(* manually unify first argument *)
+	let args,ret = match t,el_typed with
+		| TFun((_,_,ta) :: args,ret),(e :: _) ->
 			unify ctx e.etype ta p;
 			args,ret
-		| TFun(args,ret),None -> args,ret
+		| TFun(args,ret),_ -> args,ret
 		| _ ->  error "Invalid field type for generic call" p
 	in
 	begin match with_type with
@@ -403,7 +413,7 @@ let type_generic_function ctx (e,fa) el ?(using_param=None) with_type p =
 		| TMono m -> safe_mono_close ctx m p
 		| _ -> ()
 	) monos;
-	let el = match using_param with None -> el | Some e -> e :: el in
+	let el = el_typed @ el in
 	(try
 		let gctx = Generic.make_generic ctx cf.cf_params monos p in
 		let name = cf.cf_name ^ "_" ^ gctx.Generic.name in
@@ -495,8 +505,9 @@ let type_generic_function ctx (e,fa) el ?(using_param=None) with_type p =
 			| KAbstractImpl(a) ->
 				type_type ctx a.a_path p
 			| _ when stat ->
-				Builder.make_typeexpr (TClassDecl c) e.epos
-			| _ -> e
+				Builder.make_typeexpr (TClassDecl c) p
+			| _ ->
+				fa.fa_on
 		in
 		let fa = if stat then FStatic (c,cf2) else FInstance (c,tl,cf2) in
 		let e = mk (TField(e,fa)) cf2.cf_type p in
@@ -504,183 +515,30 @@ let type_generic_function ctx (e,fa) el ?(using_param=None) with_type p =
 	with Generic.Generic_Exception (msg,p) ->
 		error msg p)
 
-let rec acc_get ctx g p =
-	match g with
-	| AKNo f -> error ("Field " ^ f ^ " cannot be accessed for reading") p
-	| AKExpr e -> e
-	| AKSet _ | AKAccess _ | AKFieldSet _ -> die "" __LOC__
-	| AKUsing (et,c,cf,e,_) when ctx.in_display ->
-		(* Generate a TField node so we can easily match it for position/usage completion (issue #1968) *)
-		let ec = type_module_type ctx (TClassDecl c) None p in
-		let ec = {ec with eexpr = (TMeta((Meta.StaticExtension,[],null_pos),ec))} in
-		let t = match follow et.etype with
-			| TFun (_ :: args,ret) -> TFun(args,ret)
-			| _ -> et.etype
-		in
-		mk (TField(ec,FStatic(c,cf))) t et.epos
-	| AKUsing (et,_,cf,e,_) ->
-		(* build a closure with first parameter applied *)
-		(match follow et.etype with
-		| TFun (_ :: args,ret) ->
-			let tcallb = TFun (args,ret) in
-			let twrap = TFun ([("_e",false,e.etype)],tcallb) in
-			(* arguments might not have names in case of variable fields of function types, so we generate one (issue #2495) *)
-			let args = List.map (fun (n,o,t) ->
-				let t = if o then ctx.t.tnull t else t in
-				o,if n = "" then gen_local ctx t e.epos else alloc_var VGenerated n t e.epos (* TODO: var pos *)
-			) args in
-			let ve = alloc_var VGenerated "_e" e.etype e.epos in
-			let ecall = make_call ctx et (List.map (fun v -> mk (TLocal v) v.v_type p) (ve :: List.map snd args)) ret p in
-			let ecallb = mk (TFunction {
-				tf_args = List.map (fun (o,v) -> v,if o then Some (Texpr.Builder.make_null v.v_type v.v_pos) else None) args;
-				tf_type = ret;
-				tf_expr = (match follow ret with | TAbstract ({a_path = [],"Void"},_) -> ecall | _ -> mk (TReturn (Some ecall)) t_dynamic p);
-			}) tcallb p in
-			let ewrap = mk (TFunction {
-				tf_args = [ve,None];
-				tf_type = tcallb;
-				tf_expr = mk (TReturn (Some ecallb)) t_dynamic p;
-			}) twrap p in
-			make_call ctx ewrap [e] tcallb p
-		| _ -> die "" __LOC__)
-	| AKInline (e,f,fmode,t) ->
-		(* do not create a closure for static calls *)
-		let cmode,apply_params = match fmode with
-			| FStatic(c,_) ->
-				let f = match c.cl_kind with
-					| KAbstractImpl a when Meta.has Meta.Enum a.a_meta ->
-						(* Enum abstracts have to apply their type parameters because they are basically statics with type params (#8700). *)
-						let monos = Monomorph.spawn_constrained_monos (fun t -> t) a.a_params in
-						apply_params a.a_params monos;
-					| _ -> (fun t -> t)
-				in
-				fmode,f
-			| FInstance (c,tl,f) ->
-				(FClosure (Some (c,tl),f),(fun t -> t))
-			| _ ->
-				die "" __LOC__
-		in
-		ignore(follow f.cf_type); (* force computing *)
-		begin match f.cf_kind,f.cf_expr with
-		| _ when not (ctx.com.display.dms_inline) ->
-			mk (TField (e,cmode)) t p
-		| Method _,_->
-			let chk_class c = ((has_class_flag c CExtern) || has_class_field_flag f CfExtern) && not (Meta.has Meta.Runtime f.cf_meta) in
-			let wrap_extern c =
-				let c2 =
-					let m = c.cl_module in
-					let mpath = (fst m.m_path @ ["_" ^ snd m.m_path],(snd m.m_path) ^ "_Impl_") in
-					try
-						let rec loop mtl = match mtl with
-							| (TClassDecl c) :: _ when c.cl_path = mpath -> c
-							| _ :: mtl -> loop mtl
-							| [] -> raise Not_found
-						in
-						loop c.cl_module.m_types
-					with Not_found ->
-						let c2 = mk_class c.cl_module mpath c.cl_pos null_pos in
-						c.cl_module.m_types <- (TClassDecl c2) :: c.cl_module.m_types;
-						c2
-				in
-				let cf = try
-					PMap.find f.cf_name c2.cl_statics
-				with Not_found ->
-					let cf = {f with cf_kind = Method MethNormal} in
-					c2.cl_statics <- PMap.add cf.cf_name cf c2.cl_statics;
-					c2.cl_ordered_statics <- cf :: c2.cl_ordered_statics;
-					cf
-				in
-				let e_t = type_module_type ctx (TClassDecl c2) None p in
-				mk (TField(e_t,FStatic(c2,cf))) t p
-			in
-			let e_def = mk (TField (e,cmode)) t p in
-			begin match follow e.etype with
-				| TInst (c,_) when chk_class c ->
-					display_error ctx "Can't create closure on an extern inline member method" p;
-					e_def
-				| TAnon a ->
-					begin match !(a.a_status) with
-						| Statics c when has_class_field_flag f CfExtern ->
-							display_error ctx "Cannot create closure on @:extern inline method" p;
-							e_def
-						| Statics c when chk_class c -> wrap_extern c
-						| _ -> e_def
-					end
-				| _ -> e_def
-			end
-		| Var _,Some e ->
-			let rec loop e = Type.map_expr loop { e with epos = p; etype = apply_params e.etype } in
-			let e = loop e in
-			let e = Inline.inline_metadata e f.cf_meta in
-			let tf = apply_params f.cf_type in
-			if not (type_iseq tf e.etype) then mk (TCast(e,None)) tf e.epos
-			else e
-		| Var _,None when ctx.com.display.dms_display ->
-			 mk (TField (e,cmode)) t p
-		| Var _,None ->
-			error "Recursive inline is not supported" p
-		end
-	| AKMacro(e,cf) ->
-		(* If we are in display mode, we're probably hovering a macro call subject. Just generate a normal field. *)
-		if ctx.in_display then begin match e.eexpr with
-			| TTypeExpr (TClassDecl c) ->
-				mk (TField(e,FStatic(c,cf))) cf.cf_type e.epos
-			| _ ->
-				error "Invalid macro access" p
-		end else
-			error "Invalid macro access" p
+let abstract_using_param_type sea = match follow sea.se_this.etype with
+	| TAbstract(a,tl) when Meta.has Meta.Impl sea.se_access.fa_field.cf_meta -> apply_params a.a_params tl a.a_this
+	| _ -> sea.se_this.etype
 
-let rec build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p =
+class call_dispatcher
+	(ctx : typer)
+	(mode : access_mode)
+	(with_type : WithType.t)
+	(p : pos)
+=
 	let is_set = match mode with MSet _ -> true | _ -> false in
 	let check_assign () = if is_set then invalid_assign p in
-	match acc with
-	| AKInline (ethis,f,fmode,t) when Meta.has Meta.Generic f.cf_meta ->
-		check_assign();
-		type_generic_function ctx (ethis,fmode) el with_type p
-	| AKInline (ethis,f,fmode,t) ->
-		check_assign();
-		(match follow t with
-			| TFun (args,r) ->
-				let fcc = unify_field_call ctx fmode el args r p true in
-				fcc.fc_data ethis p true
-			| _ ->
-				error (s_type (print_context()) t ^ " cannot be called") p
-		)
-	| AKUsing (et,cl,ef,eparam,forced_inline (* TOOD? *)) when Meta.has Meta.Generic ef.cf_meta ->
-		check_assign();
-		(match et.eexpr with
-		| TField(ec,fa) ->
-			type_generic_function ctx (ec,fa) el ~using_param:(Some eparam) with_type p
-		| _ -> die "" __LOC__)
-	| AKUsing (et,cl,ef,eparam,force_inline) ->
-		begin match ef.cf_kind with
-		| Method MethMacro ->
-			let ethis = type_module_type ctx (TClassDecl cl) None p in
-			let eparam,f = push_this ctx eparam in
-			let e = build_call ~mode ctx (AKMacro (ethis,ef)) (eparam :: el) with_type p in
-			f();
-			e
-		| _ ->
-			check_assign();
-			let t = follow (field_type ctx cl [] ef p) in
-			(* for abstracts we have to apply their parameters to the static function *)
-			let t,tthis = match follow eparam.etype with
-				| TAbstract(a,tl) when Meta.has Meta.Impl ef.cf_meta -> apply_params a.a_params tl t,apply_params a.a_params tl a.a_this
-				| te -> t,te
-			in
-			let params,args,r,eparam = match t with
-				| TFun ((_,_,t1) :: args,r) ->
-					unify ctx tthis t1 eparam.epos;
-					let ef = prepare_using_field ef in
-					begin match unify_call_args ctx el args r p (ef.cf_kind = Method MethInline) (is_forced_inline (Some cl) ef) with
-					| el,TFun(args,r) -> el,args,r,eparam
-					| _ -> die "" __LOC__
-					end
-				| _ -> die "" __LOC__
-			in
-			make_call ctx ~force_inline et (eparam :: params) r p
-		end
-	| AKMacro (ethis,cf) ->
+
+object(self)
+
+	method private make_field_call fa el_typed el =
+		let fcc = unify_field_call ctx fa el_typed el p fa.fa_inline in
+		if has_class_field_flag fcc.fc_field CfAbstract then begin match fa.fa_on.eexpr with
+			| TConst TSuper -> display_error ctx (Printf.sprintf "abstract method %s cannot be accessed directly" fcc.fc_field.cf_name) p;
+			| _ -> ()
+		end;
+		fcc.fc_data()
+
+	method private macro_call ethis cf el =
 		if ctx.macro_depth > 300 then error "Stack overflow" p;
 		ctx.macro_depth <- ctx.macro_depth + 1;
 		ctx.with_type_stack <- with_type :: ctx.with_type_stack;
@@ -737,30 +595,14 @@ let rec build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p =
 		ctx.on_error <- old;
 		!ethis_f();
 		e
-	| AKNo _ | AKSet _ | AKAccess _ | AKFieldSet _ ->
-		ignore(acc_get ctx acc p);
-		die "" __LOC__
-	| AKExpr e ->
+
+	method expr_call e el =
+		check_assign();
 		let rec loop t = match follow t with
 		| TFun (args,r) ->
-			begin match e.eexpr with
-				| TField(e1,fa) when not (match fa with FEnum _ | FDynamic _ -> true | _ -> false) ->
-					begin match fa with
-						| FInstance(_,_,cf) | FStatic(_,cf) when Meta.has Meta.Generic cf.cf_meta ->
-							type_generic_function ctx (e1,fa) el with_type p
-						| _ ->
-							let fcc = unify_field_call ctx fa el args r p false in
-							if has_class_field_flag fcc.fc_field CfAbstract then begin match e1.eexpr with
-								| TConst TSuper -> display_error ctx (Printf.sprintf "abstract method %s cannot be accessed directly" fcc.fc_field.cf_name) p;
-								| _ -> ()
-							end;
-							fcc.fc_data e1 e.epos false
-					end
-				| _ ->
-					let el, tfunc = unify_call_args ctx el args r p false false in
-					let r = match tfunc with TFun(_,r) -> r | _ -> die "" __LOC__ in
-					mk (TCall (e,el)) r p
-			end
+			let el, tfunc = unify_call_args ctx el args r p false false in
+			let r = match tfunc with TFun(_,r) -> r | _ -> die "" __LOC__ in
+			mk (TCall (e,el)) r p
 		| TAbstract(a,tl) when Meta.has Meta.Callable a.a_meta ->
 			loop (Abstract.get_underlying_type a tl)
 		| TMono _ ->
@@ -781,6 +623,219 @@ let rec build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p =
 		in
 		loop e.etype
 
+	method resolve_call sea name =
+		let eparam = sea.se_this in
+		let e_name = Texpr.Builder.make_string ctx.t name null_pos in
+		self#field_call sea.se_access [eparam;e_name] []
+
+	method field_call fa el_typed el =
+		match fa.fa_field.cf_kind with
+		| Method (MethNormal | MethInline | MethDynamic) ->
+			check_assign();
+			 if Meta.has Meta.Generic fa.fa_field.cf_meta then begin
+				type_generic_function ctx fa el_typed el with_type p
+			end else
+				self#make_field_call fa el_typed el
+		| Method MethMacro ->
+			begin match el_typed with
+			| [] ->
+				self#macro_call fa.fa_on fa.fa_field el
+			| el_typed ->
+				let cur = ctx.this_stack in
+				let el' = List.map (fun e -> fst (push_this ctx e)) el_typed in
+				let e = self#macro_call fa.fa_on fa.fa_field (el' @ el) in
+				ctx.this_stack <- cur;
+				e
+			end;
+		| Var v ->
+			begin match (if is_set then v.v_write else v.v_read) with
+			| AccCall ->
+				begin match FieldAccess.resolve_accessor fa mode with
+				| AccessorFound fa' ->
+					let t = FieldAccess.get_map_function fa fa.fa_field.cf_type in
+					let e = self#field_call fa' el_typed el in
+					if not (type_iseq_strict t e.etype) then mk (TCast(e,None)) t e.epos else e
+				| AccessorAnon ->
+					(* Anons might not have the accessor defined and rely on FDynamic in such cases *)
+					let e = fa.fa_on in
+					let t = FieldAccess.get_map_function fa fa.fa_field.cf_type in
+					let tf = tfun (List.map (fun e -> e.etype) el_typed) t in
+					make_call ctx (mk (TField (e,quick_field_dynamic e.etype ("get_" ^ fa.fa_field.cf_name))) tf p) el_typed t p
+				| AccessorNotFound ->
+					error ("Could not resolve accessor") fa.fa_pos
+				| AccessorInvalid ->
+					die "Trying to resolve accessor on field that isn't AccCall" __LOC__
+				end
+			| _ ->
+				self#expr_call (FieldAccess.get_field_expr fa FCall) el
+			end
+end
+
+let rec acc_get ctx g p =
+	let inline_read fa =
+		let cf = fa.fa_field in
+		(* do not create a closure for static calls *)
+		let apply_params = match fa.fa_host with
+			| FHStatic c ->
+				(fun t -> t)
+			| FHInstance(c,tl) ->
+				(fun t -> t)
+			| FHAbstract(a,tl,c) ->
+				if Meta.has Meta.Enum a.a_meta then begin
+					(* Enum abstracts have to apply their type parameters because they are basically statics with type params (#8700). *)
+					let monos = Monomorph.spawn_constrained_monos (fun t -> t) a.a_params in
+					apply_params a.a_params monos;
+				end else
+					(fun t -> t)
+			| _ ->
+				die "" __LOC__
+		in
+		ignore(follow cf.cf_type); (* force computing *)
+		begin match cf.cf_kind,cf.cf_expr with
+		| _ when not (ctx.com.display.dms_inline) ->
+			FieldAccess.get_field_expr fa FRead
+		| Method _,_->
+			let chk_class c = ((has_class_flag c CExtern) || has_class_field_flag cf CfExtern) && not (Meta.has Meta.Runtime cf.cf_meta) in
+			let wrap_extern c =
+				let c2 =
+					let m = c.cl_module in
+					let mpath = (fst m.m_path @ ["_" ^ snd m.m_path],(snd m.m_path) ^ "_Impl_") in
+					try
+						let rec loop mtl = match mtl with
+							| (TClassDecl c) :: _ when c.cl_path = mpath -> c
+							| _ :: mtl -> loop mtl
+							| [] -> raise Not_found
+						in
+						loop c.cl_module.m_types
+					with Not_found ->
+						let c2 = mk_class c.cl_module mpath c.cl_pos null_pos in
+						c.cl_module.m_types <- (TClassDecl c2) :: c.cl_module.m_types;
+						c2
+				in
+				let cf = try
+					PMap.find cf.cf_name c2.cl_statics
+				with Not_found ->
+					let cf = {cf with cf_kind = Method MethNormal} in
+					c2.cl_statics <- PMap.add cf.cf_name cf c2.cl_statics;
+					c2.cl_ordered_statics <- cf :: c2.cl_ordered_statics;
+					cf
+				in
+				let e_t = type_module_type ctx (TClassDecl c2) None p in
+				FieldAccess.get_field_expr (FieldAccess.create e_t cf (FHStatic c2) true p) FRead
+			in
+			let e_def = FieldAccess.get_field_expr fa FRead in
+			begin match follow fa.fa_on.etype with
+				| TInst (c,_) when chk_class c ->
+					display_error ctx "Can't create closure on an extern inline member method" p;
+					e_def
+				| TAnon a ->
+					begin match !(a.a_status) with
+						| Statics c when has_class_field_flag cf CfExtern ->
+							display_error ctx "Cannot create closure on @:extern inline method" p;
+							e_def
+						| Statics c when chk_class c -> wrap_extern c
+						| _ -> e_def
+					end
+				| _ -> e_def
+			end
+		| Var _,Some e ->
+			let rec loop e = Type.map_expr loop { e with epos = p; etype = apply_params e.etype } in
+			let e = loop e in
+			let e = Inline.inline_metadata e cf.cf_meta in
+			let tf = apply_params cf.cf_type in
+			if not (type_iseq tf e.etype) then mk (TCast(e,None)) tf e.epos
+			else e
+		| Var _,None when ctx.com.display.dms_display ->
+			 FieldAccess.get_field_expr fa FRead
+		| Var _,None ->
+			error "Recursive inline is not supported" p
+		end
+	in
+	let dispatcher () = new call_dispatcher ctx MGet WithType.value p in
+	match g with
+	| AKNo f -> error ("Field " ^ f ^ " cannot be accessed for reading") p
+	| AKExpr e -> e
+	| AKAccess _ -> die "" __LOC__
+	| AKResolve(sea,name) ->
+		(dispatcher ())#resolve_call sea name
+	| AKUsingAccessor sea | AKUsingField sea when ctx.in_display ->
+		(* Generate a TField node so we can easily match it for position/usage completion (issue #1968) *)
+		let e_field = FieldAccess.get_field_expr sea.se_access FGet in
+		(* TODO *)
+		(* let ec = {ec with eexpr = (TMeta((Meta.StaticExtension,[],null_pos),ec))} in *)
+		let t = match follow e_field.etype with
+			| TFun (_ :: args,ret) -> TFun(args,ret)
+			| t -> t
+		in
+		{e_field with etype = t}
+	| AKField fa ->
+		begin match fa.fa_field.cf_kind with
+		| Method MethMacro ->
+			(* If we are in display mode, we're probably hovering a macro call subject. Just generate a normal field. *)
+			if ctx.in_display then
+				FieldAccess.get_field_expr fa FRead
+			else
+				error "Invalid macro access" p
+		| _ ->
+			if fa.fa_inline then
+				inline_read fa
+			else
+				FieldAccess.get_field_expr fa FRead
+		end
+	| AKAccessor fa ->
+		(dispatcher())#field_call fa [] []
+	| AKUsingAccessor sea ->
+		(dispatcher())#field_call sea.se_access [sea.se_this] []
+	| AKUsingField sea ->
+		let e = sea.se_this in
+		let e_field = FieldAccess.get_field_expr sea.se_access FGet in
+		(* build a closure with first parameter applied *)
+		(match follow e_field.etype with
+		| TFun ((_,_,t0) :: args,ret) ->
+			let te = abstract_using_param_type sea in
+			unify ctx te t0 e.epos;
+			let tcallb = TFun (args,ret) in
+			let twrap = TFun ([("_e",false,e.etype)],tcallb) in
+			(* arguments might not have names in case of variable fields of function types, so we generate one (issue #2495) *)
+			let args = List.map (fun (n,o,t) ->
+				let t = if o then ctx.t.tnull t else t in
+				o,if n = "" then gen_local ctx t e.epos else alloc_var VGenerated n t e.epos (* TODO: var pos *)
+			) args in
+			let ve = alloc_var VGenerated "_e" e.etype e.epos in
+			let ecall = make_call ctx e_field (List.map (fun v -> mk (TLocal v) v.v_type p) (ve :: List.map snd args)) ret p in
+			let ecallb = mk (TFunction {
+				tf_args = List.map (fun (o,v) -> v,if o then Some (Texpr.Builder.make_null v.v_type v.v_pos) else None) args;
+				tf_type = ret;
+				tf_expr = (match follow ret with | TAbstract ({a_path = [],"Void"},_) -> ecall | _ -> mk (TReturn (Some ecall)) t_dynamic p);
+			}) tcallb p in
+			let ewrap = mk (TFunction {
+				tf_args = [ve,None];
+				tf_type = tcallb;
+				tf_expr = mk (TReturn (Some ecallb)) t_dynamic p;
+			}) twrap p in
+			make_call ctx ewrap [e] tcallb p
+		| _ -> die "" __LOC__)
+
+let build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p =
+	let dispatch = new call_dispatcher ctx mode with_type p in
+	match acc with
+	| AKField fa ->
+		dispatch#field_call fa [] el
+	| AKUsingField sea ->
+		let eparam = sea.se_this in
+		dispatch#field_call sea.se_access [eparam] el
+	| AKNo _ | AKAccess _ | AKResolve _ ->
+		ignore(acc_get ctx acc p);
+		die "" __LOC__
+	| AKAccessor fa ->
+		let e = dispatch#field_call fa [] [] in
+		dispatch#expr_call e el
+	| AKUsingAccessor sea ->
+		let e = dispatch#field_call sea.se_access [sea.se_this] [] in
+		dispatch#expr_call e el
+	| AKExpr e ->
+		dispatch#expr_call e el
+
 let type_bind ctx (e : texpr) (args,ret) params p =
 	let vexpr v = mk (TLocal v) v.v_type p in
 	let acount = ref 0 in
@@ -909,8 +964,16 @@ let array_access ctx e1 e2 mode p =
 	given chain of fields as the `path` argument and an `access_mode->access_kind` getter for some starting expression as `e`,
 	return a new `access_mode->access_kind` getter for the whole field access chain.
 *)
-let field_chain ctx path e =
-	List.fold_left (fun e (f,_,p) ->
-		let e = acc_get ctx (e MGet WithType.value (* WITHTYPETODO *)) p in
-		type_field_default_cfg ctx e f p
-	) e path
+let field_chain ctx path access mode with_type =
+	let rec loop access path = match path with
+		| [] ->
+			access
+		| [(name,_,p)] ->
+			let e = acc_get ctx access p in
+			type_field_default_cfg ctx e name p mode with_type
+		| (name,_,p) :: path ->
+			let e = acc_get ctx access p in
+			let access = type_field_default_cfg ctx e name p MGet WithType.value in
+			loop access path
+	in
+	loop access path

+ 121 - 202
src/typing/fields.ml

@@ -88,7 +88,7 @@ let check_constructor_access ctx c f p =
 	if (Meta.has Meta.CompilerGenerated f.cf_meta) then display_error ctx (error_msg (No_constructor (TClassDecl c))) p;
 	if not (can_access ctx c f true || extends ctx.curclass c) && not ctx.untyped then display_error ctx (Printf.sprintf "Cannot access private constructor of %s" (s_class_path c)) p
 
-let check_no_closure_meta ctx fa mode p =
+let check_no_closure_meta ctx cf fa mode p =
 	match mode with
 	| MGet | MSet _ when not (DisplayPosition.display_position#enclosed_in p) ->
 		let check_field f cl_meta =
@@ -101,95 +101,109 @@ let check_no_closure_meta ctx fa mode p =
 					error ("Method " ^ f.cf_name ^ " cannot be used as a value") p
 			| _ -> ()
 		in
-		begin match fa with
-		| FStatic (c, ({ cf_kind = Method _} as f)) -> check_field f c.cl_meta
-		| FInstance (c, _, ({ cf_kind = Method _} as f)) -> check_field f c.cl_meta
-		| FClosure (Some (c, _), ({ cf_kind = Method _} as f)) -> check_field f c.cl_meta
-		| FClosure (None, ({ cf_kind = Method _} as f)) -> check_field f []
-		| FAnon ({ cf_kind = Method _} as f) -> check_field f []
-		| _ -> ()
+		begin match cf.cf_kind with
+		| Method _ ->
+			let meta = match fa with
+				| FHStatic c | FHInstance(c,_) | FHAbstract(_,_,c) -> c.cl_meta
+				| _ -> []
+			in
+			check_field cf meta
+		| _ ->
+			()
 		end
 	| _ ->
 		()
 
-let field_access ctx mode f fmode t e p =
+let check_field_access ctx c f stat p =
+	if not ctx.untyped && not (can_access ctx c f stat) then
+		display_error ctx ("Cannot access private field " ^ f.cf_name) p
+
+let field_access ctx mode f famode e p =
 	let is_set = match mode with MSet _ -> true | _ -> false in
-	check_no_closure_meta ctx fmode mode p;
+	check_no_closure_meta ctx f famode mode p;
 	let bypass_accessor = if ctx.bypass_accessor > 0 then (ctx.bypass_accessor <- ctx.bypass_accessor - 1; true) else false in
-	let fnormal() = AKExpr (mk (TField (e,fmode)) t p) in
-	let normal() =
-		match follow e.etype with
-		| TAnon a ->
-			(match !(a.a_status) with
-			| EnumStatics en ->
-				let c = (try PMap.find f.cf_name en.e_constrs with Not_found -> die "" __LOC__) in
-				let fmode = FEnum (en,c) in
-				AKExpr (mk (TField (e,fmode)) t p)
-			| _ -> fnormal())
-		| _ -> fnormal()
-	in
+	let make_access inline = FieldAccess.create e f famode inline p in
 	match f.cf_kind with
 	| Method m ->
+		let normal () = AKField(make_access false) in
 		if is_set && m <> MethDynamic && not ctx.untyped then error "Cannot rebind this method : please use 'dynamic' before method declaration" p;
-		begin match ctx.curfun,e.eexpr with
-		| (FunMemberAbstract | FunMemberAbstractLocal),TTypeExpr(TClassDecl ({cl_kind = KAbstractImpl a} as c)) when c == ctx.curclass && Meta.has Meta.Impl f.cf_meta ->
-			let e = mk (TField(e,fmode)) t p in
-			let ethis = get_this ctx p in
-			let ethis = {ethis with etype = TAbstract(a,List.map snd a.a_params)} in
-			AKUsing(e,ctx.curclass,f,ethis,false)
-		| _ ->
-			(match m, mode with
-			| MethInline, _ -> AKInline (e,f,fmode,t)
-			| MethMacro, MGet -> display_error ctx "Macro functions must be called immediately" p; normal()
-			| MethMacro, MCall _ -> AKMacro (e,f)
+		let maybe_check_visibility c static =
+			(* For overloads we have to resolve the actual field before we can check accessibility. *)
+			begin match mode with
+			| MCall _ when has_class_field_flag f CfOverload ->
+				()
+			| _ ->
+				check_field_access ctx c f static p;
+			end;
+		in
+		let default () =
+			match m, mode with
+			| MethInline, _ ->
+				AKField (make_access true)
+			| MethMacro, MGet ->
+				display_error ctx "Macro functions must be called immediately" p; normal()
 			| _ , MGet ->
-				let cmode = (match fmode with
-					| FInstance(_, _, cf) | FStatic(_, cf) when Meta.has Meta.Generic cf.cf_meta -> display_error ctx "Cannot create closure on generic function" p; fmode
-					| FInstance (c,tl,cf) -> FClosure (Some (c,tl),cf)
-					| FStatic _ | FEnum _ -> fmode
-					| FAnon f -> FClosure (None, f)
-					| FDynamic _ | FClosure _ -> die "" __LOC__
-				) in
-				AKExpr (mk (TField (e,cmode)) t p)
-			| _ -> normal())
-		end
+				if Meta.has Meta.Generic f.cf_meta then display_error ctx "Cannot create closure on generic function" p;
+				normal()
+			| _ ->
+				normal()
+		in
+		begin match famode with
+		| FHInstance(c,tl) ->
+			if e.eexpr = TConst TSuper then (match mode,f.cf_kind with
+				| MGet,Var {v_read = AccCall }
+				| MSet _,Var {v_write = AccCall }
+				| MCall _,Var {v_read = AccCall } ->
+					()
+				| MCall _, Var _ ->
+					display_error ctx "Cannot access superclass variable for calling: needs to be a proper method" p
+				| MCall _, _ ->
+					()
+				| MGet,Var _
+				| MSet _,Var _ when ctx.com.platform = Flash && has_class_flag c CExtern ->
+					()
+				| _, Method _ ->
+					display_error ctx "Cannot create closure on super method" p
+				| _ ->
+					display_error ctx "Normal variables cannot be accessed with 'super', use 'this' instead" p);
+			(* We need the actual class type (i.e. a potential child class) for visibility checks. *)
+			begin match follow e.etype with
+			| TInst(c,_) ->
+				maybe_check_visibility c false;
+			| _ ->
+				()
+			end;
+			default();
+		| FHStatic c ->
+			maybe_check_visibility c true;
+			default()
+		| FHAnon ->
+			default()
+		| FHAbstract(a,tl,c) ->
+			maybe_check_visibility c true;
+			let sea = make_abstract_static_extension_access a tl c f e false p in
+			AKUsingField sea
+		end;
 	| Var v ->
+		let normal inline =
+			AKField (make_access inline)
+		in
 		match (match mode with MGet | MCall _ -> v.v_read | MSet _ -> v.v_write) with
 		| AccNo when not (Meta.has Meta.PrivateAccess ctx.meta) ->
 			(match follow e.etype with
-			| TInst (c,_) when extends ctx.curclass c || can_access ctx c { f with cf_flags = unset_flag f.cf_flags (int_of_class_field_flag CfPublic) } false -> normal()
+			| TInst (c,_) when extends ctx.curclass c || can_access ctx c { f with cf_flags = unset_flag f.cf_flags (int_of_class_field_flag CfPublic) } false -> normal false
 			| TAnon a ->
 				(match !(a.a_status) with
-				| Statics c2 when ctx.curclass == c2 || can_access ctx c2 { f with cf_flags = unset_flag f.cf_flags (int_of_class_field_flag CfPublic) } true -> normal()
-				| _ -> if ctx.untyped then normal() else AKNo f.cf_name)
+				| Statics c2 when ctx.curclass == c2 || can_access ctx c2 { f with cf_flags = unset_flag f.cf_flags (int_of_class_field_flag CfPublic) } true -> normal false
+				| _ -> if ctx.untyped then normal false else AKNo f.cf_name)
 			| _ ->
-				if ctx.untyped then normal() else AKNo f.cf_name)
+				if ctx.untyped then normal false else AKNo f.cf_name)
 		| AccNormal | AccNo ->
-			(*
-				if we are reading from a read-only variable on an anonymous object, it might actually be a method, so make sure to create a closure
-			*)
-			let is_maybe_method() =
-				match v.v_write, follow t, follow e.etype with
-				| (AccNo | AccNever), TFun _, TAnon a ->
-					(match !(a.a_status) with
-					| Statics _ | EnumStatics _ -> false
-					| _ -> true)
-				| _ -> false
-			in
-			if mode = MGet && is_maybe_method() then
-				AKExpr (mk (TField (e,FClosure (None,f))) t p)
-			else
-				normal()
-		| AccCall | AccInline when ctx.in_display ->
-			normal()
+			normal false
+		| AccCall when ctx.in_display && DisplayPosition.display_position#enclosed_in p ->
+			normal false
 		| AccCall ->
 			let m = (match mode with MSet _ -> "set_" | _ -> "get_") ^ f.cf_name in
-			let is_abstract_this_access () = match e.eexpr,ctx.curfun with
-				| TTypeExpr (TClassDecl ({cl_kind = KAbstractImpl _} as c)),(FunMemberAbstract | FunMemberAbstractLocal) when Meta.has Meta.Impl f.cf_meta  ->
-					c == ctx.curclass
-				| _ ->
-					false
-			in
 			let bypass_accessor =
 				bypass_accessor
 				||
@@ -209,30 +223,22 @@ let field_access ctx mode f fmode t e p =
 					display_error ctx "This field cannot be accessed because it is not a real variable" p;
 					display_error ctx "Add @:isVar here to enable it" f.cf_pos;
 				end;
-				AKExpr (mk (TField (e,fmode)) t p)
-			) else if is_abstract_this_access() then begin
-				let this = get_this ctx p in
-				if is_set then begin
-					let c,a = match ctx.curclass with {cl_kind = KAbstractImpl a} as c -> c,a | _ -> die "" __LOC__ in
-					let f = PMap.find m c.cl_statics in
-					(* we don't have access to the type parameters here, right? *)
-					(* let t = apply_params a.a_params pl (field_type ctx c [] f p) in *)
-					let t = (field_type ctx c [] f p) in
-					let ef = mk (TField (e,FStatic (c,f))) t p in
-					AKUsing (ef,c,f,this,false)
-				end else
-					AKExpr (make_call ctx (mk (TField (e,quick_field_dynamic e.etype m)) (tfun [this.etype] t) p) [this] t p)
-			end else if is_set then
-				AKSet (e,t,f)
-			else
-				AKExpr (make_call ctx (mk (TField (e,quick_field_dynamic e.etype m)) (tfun [] t) p) [] t p)
+				normal false
+			)
+			else begin match famode with
+			| FHAbstract(a,tl,c) ->
+				let sea = make_abstract_static_extension_access a tl c f e false p in
+				AKUsingAccessor sea
+			| _ ->
+				AKAccessor (make_access false)
+			end
 		| AccNever ->
-			if ctx.untyped then normal() else AKNo f.cf_name
+			if ctx.untyped then normal false else AKNo f.cf_name
 		| AccInline ->
-			AKInline (e,f,fmode,t)
+			normal true
 		| AccCtor ->
-			(match ctx.curfun, fmode with
-				| FunConstructor, FInstance(c,_,_) when c == ctx.curclass -> normal()
+			(match ctx.curfun, famode with
+				| FunConstructor, FHInstance(c,_) when c == ctx.curclass -> normal false
 				| _ -> AKNo f.cf_name
 			)
 		| AccRequire (r,msg) ->
@@ -266,9 +272,8 @@ let rec using_field ctx mode e i p =
 				| TFun((_,_,(TType({t_path = ["haxe";"macro"],"ExprOf"},[t0]) | t0)) :: args,r) ->
 					if is_dynamic && follow t0 != t_dynamic then raise Not_found;
 					let e = unify_static_extension ctx e t0 p in
-					let et = type_module_type ctx (TClassDecl c) None p in
 					ImportHandling.mark_import_position ctx pc;
-					AKUsing (mk (TField (et,FStatic (c,cf))) t p,c,cf,e,false)
+					AKUsingField (make_static_extension_access c cf e false p)
 				| _ ->
 					raise Not_found
 			end
@@ -289,17 +294,13 @@ let rec using_field ctx mode e i p =
 		(* global using *)
 		let acc = loop ctx.g.global_using in
 		(match acc with
-		| AKUsing (_,c,_,_,_) -> add_dependency ctx.m.curmod c.cl_module
+		| AKUsingField {se_access = {fa_host = FHStatic c}} -> add_dependency ctx.m.curmod c.cl_module
 		| _ -> die "" __LOC__);
 		acc
 	with Not_found ->
 		if not !check_constant_struct then raise Not_found;
 		remove_constant_flag e.etype (fun ok -> if ok then using_field ctx mode e i p else raise Not_found)
 
-let check_field_access ctx c f stat p =
-	if not ctx.untyped && not (can_access ctx c f stat) then
-		display_error ctx ("Cannot access private field " ^ f.cf_name) p
-
 let emit_missing_field_error ctx i t pfield =
 	display_error ctx (StringError.string_error i (string_source t) (s_type (print_context()) t ^ " has no field " ^ i)) pfield
 
@@ -371,30 +372,7 @@ let rec type_field cfg ctx e i p mode (with_type : WithType.t) =
 		in
 		(try
 			let c2, t , f = class_field ctx c params i p in
-			if e.eexpr = TConst TSuper then (match mode,f.cf_kind with
-				| MGet,Var {v_read = AccCall }
-				| MSet _,Var {v_write = AccCall }
-				| MCall _,Var {v_read = AccCall } ->
-					()
-				| MCall _, Var _ ->
-					display_error ctx "Cannot access superclass variable for calling: needs to be a proper method" pfield
-				| MCall _, _ ->
-					()
-				| MGet,Var _
-				| MSet _,Var _ when ctx.com.platform = Flash && (match c2 with Some (c2, _) -> has_class_flag c2 CExtern | _ -> false) ->
-					()
-				| _, Method _ ->
-					display_error ctx "Cannot create closure on super method" p
-				| _ ->
-					display_error ctx "Normal variables cannot be accessed with 'super', use 'this' instead" pfield);
-			(* For overloads we have to resolve the actual field before we can check accessibility. *)
-			begin match mode with
-			| MCall _ when has_class_field_flag f CfOverload ->
-				()
-			| _ ->
-				check_field_access ctx c f false pfield;
-			end;
-			field_access ctx mode f (match c2 with None -> FAnon f | Some (c,tl) -> FInstance (c,tl,f)) (apply_params c.cl_params params t) e p
+			field_access ctx mode f (match c2 with None -> FHAnon | Some (c,tl) -> FHInstance (c,tl)) e p
 		with Not_found -> try
 			begin match e.eexpr with
 				| TConst TSuper -> raise Not_found
@@ -445,23 +423,20 @@ let rec type_field cfg ctx e i p mode (with_type : WithType.t) =
 					| _ -> display_error ctx ("Cannot access private field " ^ i) pfield
 				end;
 			end;
-			let fmode, ft = (match !(a.a_status) with
-				| Statics c -> FStatic (c,f), field_type ctx c [] f p
-				| EnumStatics e ->
-					let ef = try PMap.find f.cf_name e.e_constrs with Not_found -> die "" __LOC__ in
-					let t = enum_field_type ctx e ef p in
-					FEnum (e,ef),t
+			let access fmode =
+				field_access ctx mode f fmode e p
+			in
+			begin match !(a.a_status) with
+				| Statics c ->
+					access (FHStatic c)
+				| EnumStatics en ->
+					let c = (try PMap.find f.cf_name en.e_constrs with Not_found -> die "" __LOC__) in
+					let fmode = FEnum (en,c) in
+					let t = enum_field_type ctx en c p in
+					AKExpr (mk (TField (e,fmode)) t p)
 				| _ ->
-					match f.cf_params with
-					| [] ->
-						FAnon f, Type.field_type f
-					| l ->
-						(* handle possible constraints *)
-						let monos = Monomorph.spawn_constrained_monos (fun t -> t) f.cf_params in
-						let t = apply_params f.cf_params monos f.cf_type in
-						FAnon f, t
-			) in
-			field_access ctx mode f fmode ft e p
+					access FHAnon
+			end
 		with Not_found -> try
 				match !(a.a_status) with
 				| Statics {cl_kind = KAbstractImpl a} when does_forward a true ->
@@ -482,7 +457,7 @@ let rec type_field cfg ctx e i p mode (with_type : WithType.t) =
 			cf_kind = Var { v_read = AccNormal; v_write = (match mode with MSet _ -> AccNormal | MGet | MCall _ -> AccNo) };
 		} in
 		let access f =
-			field_access ctx mode f (FAnon f) (Type.field_type f) e p
+			field_access ctx mode f FHAnon e p
 		in
 		begin match Monomorph.classify_constraints r with
 		| CStructural(fields,is_open) ->
@@ -531,58 +506,11 @@ let rec type_field cfg ctx e i p mode (with_type : WithType.t) =
 		(try
 			let c = (match a.a_impl with None -> raise Not_found | Some c -> c) in
 			let f = PMap.find i c.cl_statics in
-			check_field_access ctx c f true pfield;
-			let field_type f =
-				if not (Meta.has Meta.Impl f.cf_meta) then begin
-					static_abstract_access_through_instance := true;
-					raise Not_found;
-				end;
-				let t = field_type ctx c [] f p in
-				apply_params a.a_params pl t
-			in
-			let et = type_module_type ctx (TClassDecl c) None p in
-			let field_expr f t = mk (TField (et,FStatic (c,f))) t p in
-			(match mode, f.cf_kind with
-			| (MGet | MCall _), Var {v_read = AccCall } when ctx.in_display && DisplayPosition.display_position#enclosed_in p ->
-				let ef = field_expr f (field_type f) in
-				AKExpr(ef)
-			| (MGet | MCall _), Var {v_read = AccCall } ->
-				(* getter call *)
-				let getter = PMap.find ("get_" ^ f.cf_name) c.cl_statics in
-				let t = field_type getter in
-				let r = match follow t with TFun(_,_) -> field_type f | _ -> raise Not_found in
-				let ef = field_expr getter t in
-				AKExpr(make_call ctx ef [e] r p)
-			| MSet _, Var {v_write = AccCall } ->
-				let f = PMap.find ("set_" ^ f.cf_name) c.cl_statics in
-				let t = field_type f in
-				let ef = field_expr f t in
-				AKUsing (ef,c,f,e,false)
-			| (MGet | MCall _), Var {v_read = AccNever} ->
-				AKNo f.cf_name
-			| (MGet | MCall _), _ ->
-				let rec loop cfl = match cfl with
-					| [] -> error (Printf.sprintf "Field %s cannot be called on %s" f.cf_name (s_type (print_context()) e.etype)) pfield
-					| cf :: cfl ->
-						match follow (apply_params a.a_params pl (monomorphs cf.cf_params cf.cf_type)) with
-							| TFun((_,_,t1) :: _,_) when type_iseq t1 (Abstract.get_underlying_type a pl) ->
-								cf
-							| _ ->
-								loop cfl
-				in
-				let f = match f.cf_overloads with
-					| [] -> f
-					| cfl -> loop (f :: cfl)
-				in
-				let t = field_type f in
-				begin match follow t with
-					| TFun((_,_,t1) :: _,_) -> ()
-					| _ -> error ("Invalid call to static function " ^ i ^ " through abstract instance") pfield
-				end;
-				let ef = field_expr f t in
-				AKUsing (ef,c,f,e,false)
-			| MSet _, _ ->
-				error "This operation is unsupported" p)
+			if not (Meta.has Meta.Impl f.cf_meta) then begin
+				static_abstract_access_through_instance := true;
+				raise Not_found;
+			end;
+			field_access ctx mode f (FHAbstract(a,pl,c)) e p
 		with Not_found -> try
 			if does_forward a false then
 				let underlying_type = Abstract.get_underlying_type ~return_first:true a pl in
@@ -602,17 +530,8 @@ let rec type_field cfg ctx e i p mode (with_type : WithType.t) =
 					| Some c,Some cf -> c,cf
 					| _ -> raise Not_found
 				in
-				let et = type_module_type ctx (TClassDecl c) None p in
-				let t = apply_params a.a_params pl (field_type ctx c [] cf p) in
-				let ef = mk (TField (et,FStatic (c,cf))) t p in
-				let r = match follow t with
-					| TFun(_,r) -> r
-					| _ -> die "" __LOC__
-				in
-				if is_write then
-					AKFieldSet(e,ef,i,r)
-				else
-					AKExpr ((!build_call_ref) ctx (AKUsing(ef,c,cf,e,false)) [EConst (String(i,SDoubleQuotes)),p] NoValue p)
+				let sea = make_abstract_static_extension_access a pl c cf e false p in
+				AKResolve(sea,i)
 			in
 			if not (TypeFieldConfig.allow_resolve cfg) then raise Not_found;
 			get_resolve (is_set)

+ 221 - 156
src/typing/typer.ml

@@ -353,7 +353,8 @@ let rec type_ident_raise ctx i p mode with_type =
 						let cf = { (mk_field v.v_name v.v_type e.epos null_pos) with cf_params = params; cf_expr = Some e; cf_kind = Method MethInline } in
 						add_class_flag c CExtern;
 						c.cl_fields <- PMap.add cf.cf_name cf PMap.empty;
-						AKInline (mk (TConst TNull) (TInst (c,[])) p, cf, FInstance(c,[],cf), t)
+						let e = mk (TConst TNull) (TInst (c,[])) p in
+						AKField (FieldAccess.create e cf (FHInstance(c,[])) true p)
 				end
 			| _ ->
 				AKExpr (mk (TLocal v) t p))
@@ -363,15 +364,25 @@ let rec type_ident_raise ctx i p mode with_type =
 		(* member variable lookup *)
 		if ctx.curfun = FunStatic then raise Not_found;
 		let c , t , f = class_field ctx ctx.curclass (List.map snd ctx.curclass.cl_params) i p in
-		field_access ctx mode f (match c with None -> FAnon f | Some (c,tl) -> FInstance (c,tl,f)) t (get_this ctx p) p
+		field_access ctx mode f (match c with None -> FHAnon | Some (c,tl) -> FHInstance (c,tl)) (get_this ctx p) p
 	with Not_found -> try
 		(* static variable lookup *)
 		let f = PMap.find i ctx.curclass.cl_statics in
-		if Meta.has Meta.Impl f.cf_meta && not (Meta.has Meta.Impl ctx.curfield.cf_meta) && not (Meta.has Meta.Enum f.cf_meta) then
+		let is_impl = Meta.has Meta.Impl f.cf_meta in
+		let is_enum = Meta.has Meta.Enum f.cf_meta in
+		if is_impl && not (Meta.has Meta.Impl ctx.curfield.cf_meta) && not is_enum then
 			error (Printf.sprintf "Cannot access non-static field %s from static method" f.cf_name) p;
-		let e = type_type ctx ctx.curclass.cl_path p in
-		(* check_locals_masking already done in type_type *)
-		field_access ctx mode f (FStatic (ctx.curclass,f)) (field_type ctx ctx.curclass [] f p) e p
+		let e,fa = match ctx.curclass.cl_kind with
+			| KAbstractImpl a when is_impl && not is_enum ->
+				let tl = List.map snd a.a_params in
+				let e = get_this ctx p in
+				let e = {e with etype = TAbstract(a,tl)} in
+				e,FHAbstract(a,tl,ctx.curclass)
+			| _ ->
+				let e = type_type ctx ctx.curclass.cl_path p in
+				e,FHStatic ctx.curclass
+		in
+		field_access ctx mode f fa e p
 	with Not_found -> try
 		(* module-level statics *)
 		(match ctx.m.curmod.m_statics with
@@ -379,7 +390,7 @@ let rec type_ident_raise ctx i p mode with_type =
 		| Some c ->
 			let f = PMap.find i c.cl_statics in
 			let e = type_module_type ctx (TClassDecl c) None p in
-			field_access ctx mode f (FStatic (c,f)) (field_type ctx c [] f p) e p
+			field_access ctx mode f (FHStatic c) e p
 		)
 	with Not_found -> try
 		let wrap e = if is_set then
@@ -400,13 +411,13 @@ let rec type_ident_raise ctx i p mode with_type =
 							loop l
 						else begin
 							let et = type_module_type ctx (TClassDecl c) None p in
-							let fa = FStatic(c,cf) in
-							let t = monomorphs cf.cf_params cf.cf_type in
+							let inline = match cf.cf_kind with
+								| Var {v_read = AccInline} -> true
+								|  _ -> false
+							in
+							let fa = FieldAccess.create et cf (FHAbstract(a,List.map snd a.a_params,c)) inline p in
 							ImportHandling.mark_import_position ctx pt;
-							begin match cf.cf_kind with
-								| Var {v_read = AccInline} -> AKInline(et,cf,fa,t)
-								| _ -> AKExpr (mk (TField(et,fa)) t p)
-							end
+							AKField fa
 						end
 					with Not_found ->
 						loop l
@@ -501,7 +512,55 @@ let unify_int ctx e k =
 		unify ctx e.etype ctx.t.tint e.epos;
 		true
 
-let rec type_binop ctx op e1 e2 is_assign_op with_type p =
+let rec type_assign ctx e1 e2 with_type p =
+	let e1 = type_access ctx (fst e1) (snd e1) (MSet (Some e2)) with_type in
+	let type_rhs with_type = type_expr ctx e2 with_type in
+	let assign_to e1 =
+		let e2 = type_rhs (WithType.with_type e1.etype) in
+		let e2 = AbstractCast.cast_or_unify ctx e1.etype e2 p in
+		check_assign ctx e1;
+		(match e1.eexpr , e2.eexpr with
+		| TLocal i1 , TLocal i2 when i1 == i2 -> error "Assigning a value to itself" p
+		| TField ({ eexpr = TConst TThis },FInstance (_,_,f1)) , TField ({ eexpr = TConst TThis },FInstance (_,_,f2)) when f1 == f2 ->
+			error "Assigning a value to itself" p
+		| _ , _ -> ());
+		mk (TBinop (OpAssign,e1,e2)) e1.etype p
+	in
+	(match e1 with
+	| AKNo s -> error ("Cannot access field or identifier " ^ s ^ " for writing") p
+	| AKUsingField _ ->
+		error "Invalid operation" p
+	| AKExpr { eexpr = TLocal { v_kind = VUser TVOLocalFunction; v_name = name } } ->
+		error ("Cannot access function " ^ name ^ " for writing") p
+	| AKField fa ->
+		let ef = FieldAccess.get_field_expr fa FWrite in
+		assign_to ef
+	| AKExpr e1  ->
+		assign_to e1
+	| AKAccessor fa ->
+		let fa_set = match FieldAccess.resolve_accessor fa (MSet (Some e2)) with
+			| AccessorFound fa -> fa
+			| _ -> error "Could not resolve accessor" p
+		in
+		let dispatcher = new call_dispatcher ctx (MCall [e2]) with_type p in
+		dispatcher#field_call fa_set [] [e2]
+	| AKAccess(a,tl,c,ebase,ekey) ->
+		let e2 = type_rhs WithType.value in
+		mk_array_set_call ctx (AbstractCast.find_array_access ctx a tl ekey (Some e2) p) c ebase p
+	| AKResolve(sea,name) ->
+		let eparam = sea.se_this in
+		let e_name = Texpr.Builder.make_string ctx.t name null_pos in
+		(new call_dispatcher ctx (MCall [e2]) with_type p)#field_call sea.se_access [eparam;e_name] [e2]
+	| AKUsingAccessor sea ->
+		let fa_set = match FieldAccess.resolve_accessor sea.se_access (MSet (Some e2)) with
+			| AccessorFound fa -> fa
+			| _ -> error "Could not resolve accessor" p
+		in
+		let dispatcher = new call_dispatcher ctx (MCall [e2]) with_type p in
+		dispatcher#field_call fa_set [sea.se_this] [e2]
+	)
+
+and type_binop ctx op e1 e2 is_assign_op with_type p =
 	let type_non_assign_op abstract_overload_only =
 		(* If the with_type is an abstract which has exactly one applicable @:op method, we can promote it
 		   to the individual arguments (issue #2786). *)
@@ -522,59 +581,14 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p =
 		let e1 = type_expr ctx e1 wt in
 		type_binop2 ~abstract_overload_only ctx op e1 e2 is_assign_op wt p
 	in
+	let e2_syntax = e2 in
 	match op with
 	| OpAssign ->
-		let e1 = type_access ctx (fst e1) (snd e1) (MSet (Some e2)) with_type in
-		let e2 with_type = type_expr ctx e2 with_type in
-		(match e1 with
-		| AKNo s -> error ("Cannot access field or identifier " ^ s ^ " for writing") p
-		| AKExpr { eexpr = TLocal { v_kind = VUser TVOLocalFunction; v_name = name } } ->
-			error ("Cannot access function " ^ name ^ " for writing") p
-		| AKExpr e1  ->
-			let e2 = e2 (WithType.with_type e1.etype) in
-			let e2 = AbstractCast.cast_or_unify ctx e1.etype e2 p in
-			check_assign ctx e1;
-			(match e1.eexpr , e2.eexpr with
-			| TLocal i1 , TLocal i2 when i1 == i2 -> error "Assigning a value to itself" p
-			| TField ({ eexpr = TConst TThis },FInstance (_,_,f1)) , TField ({ eexpr = TConst TThis },FInstance (_,_,f2)) when f1 == f2 ->
-				error "Assigning a value to itself" p
-			| _ , _ -> ());
-			mk (TBinop (op,e1,e2)) e1.etype p
-		| AKSet (e,t,cf) ->
-			let e2 = e2 (WithType.with_type t) in
-			let e2 = AbstractCast.cast_or_unify ctx t e2 p in
-			make_call ctx (mk (TField (e,quick_field_dynamic e.etype ("set_" ^ cf.cf_name))) (tfun [t] t) p) [e2] t p
-		| AKAccess(a,tl,c,ebase,ekey) ->
-			let e2 = e2 WithType.value in
-			mk_array_set_call ctx (AbstractCast.find_array_access ctx a tl ekey (Some e2) p) c ebase p
-		| AKFieldSet(ethis,e1,fname,t) ->
-			let e2 = e2 (WithType.with_type t) in
-			begin match follow e1.etype with
-				| TFun([_;_;(_,_,t)],_) -> unify ctx e2.etype t e2.epos;
-				| _ -> die "" __LOC__
-			end;
-			make_call ctx e1 [ethis;Texpr.Builder.make_string ctx.t fname null_pos;e2] t p
-		| AKUsing(ef,_,_,et,_) ->
-			(* this must be an abstract setter *)
-			let e2,ret = match follow ef.etype with
-				| TFun([_;(_,_,t)],ret) ->
-					let e2 = e2 (WithType.with_type t) in
-					AbstractCast.cast_or_unify ctx t e2 p,ret
-				| _ ->  error "Invalid field type for abstract setter" p
-			in
-			make_call ctx ef [et;e2] ret p
-		| AKInline _ | AKMacro _ ->
-			die "" __LOC__)
+		type_assign ctx e1 e2 with_type p
 	| OpAssignOp (OpBoolAnd | OpBoolOr) ->
 		error "The operators ||= and &&= are not supported" p
 	| OpAssignOp op ->
-		(match type_access ctx (fst e1) (snd e1) (MSet (Some e2)) with_type with
-		| AKNo s ->
-			(* try abstract operator overloading *)
-			(try type_non_assign_op true
-			with Not_found -> error ("Cannot access field or identifier " ^ s ^ " for writing") p
-			)
-		| AKExpr e ->
+		let handle e =
 			let save = save_locals ctx in
 			let v = gen_local ctx e.etype e.epos in
 			let has_side_effect = OptimizerTexpr.has_side_effect e in
@@ -624,7 +638,24 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p =
 					]) eop.etype eop.epos
 				else
 					eop)
-		| AKSet (e,t,cf) ->
+		in
+		(match type_access ctx (fst e1) (snd e1) (MSet (Some e2)) with_type with
+		| AKNo s ->
+			(* try abstract operator overloading *)
+			(try type_non_assign_op true
+			with Not_found -> error ("Cannot access field or identifier " ^ s ^ " for writing") p
+			)
+		| AKUsingField _ ->
+			error "Invalid operation" p
+		| AKField fa ->
+			let e1 = FieldAccess.get_field_expr fa FWrite in
+			handle e1
+		| AKExpr e ->
+			handle e
+		| AKAccessor fa ->
+			let e = fa.fa_on in
+			let cf = fa.fa_field in
+			let t = (FieldAccess.get_field_expr fa FCall).etype in
 			let l = save_locals ctx in
 			let v = gen_local ctx e.etype e.epos in
 			let ev = mk (TLocal v) e.etype p in
@@ -642,9 +673,18 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p =
 				mk (TVar (v,Some e)) ctx.t.tvoid p;
 				e'
 			]) t p
-		| AKUsing(ef,c,cf,et,_) ->
+		| AKUsingAccessor sea ->
+			let fa_set = match FieldAccess.resolve_accessor sea.se_access (MSet (Some e2_syntax)) with
+				| AccessorFound fa -> fa
+				| _ -> error "Could not resolve accessor" p
+			in
+			let ef = FieldAccess.get_field_expr fa_set FWrite in
+			let et = sea.se_this in
 			(* abstract setter + getter *)
-			let ta = match c.cl_kind with KAbstractImpl a -> TAbstract(a,Monomorph.spawn_constrained_monos (fun t -> t) a.a_params) | _ -> die "" __LOC__ in
+			let ta = match sea.se_access.fa_host with
+				| FHAbstract(a,tl,_) -> TAbstract(a,tl)
+				| _ -> die "" __LOC__
+			in
 			let ret = match follow ef.etype with
 				| TFun([_;_],ret) -> ret
 				| _ -> error "Invalid field type for abstract setter" p
@@ -669,7 +709,7 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p =
 							needs_temp_var e1
 						| _ -> true
 					in
-					if has_class_field_flag cf CfModifiesThis then
+					if has_class_field_flag fa_set.fa_field CfModifiesThis then
 						match et.eexpr with
 						| TField (target,fa) when needs_temp_var target->
 							let tmp = gen_local ctx target.etype target.epos in
@@ -691,7 +731,7 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p =
 			in
 			let ev = mk (TLocal v) ta p in
 			(* this relies on the fact that cf_name is set_name *)
-			let getter_name = String.sub cf.cf_name 4 (String.length cf.cf_name - 4) in
+			let getter_name = sea.se_access.fa_field.cf_name in
 			let get = type_binop ctx op (EField ((EConst (Ident v.v_name),p),getter_name),p) e2 true with_type p in
 			unify ctx get.etype ret p;
 			l();
@@ -755,10 +795,9 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p =
 			in
 			save();
 			e
-		| AKFieldSet _ ->
+		| AKResolve _ ->
 			error "Invalid operation" p
-		| AKInline _ | AKMacro _ ->
-			die "" __LOC__)
+		)
 	| _ ->
 		type_non_assign_op false
 
@@ -1107,7 +1146,8 @@ and type_binop2 ?(abstract_overload_only=false) ctx op (e1 : texpr) (e2 : Ast.ex
 
 and type_unop ctx op flag e p =
 	let set = (op = Increment || op = Decrement) in
-	let acc = type_access ctx (fst e) (snd e) (if set then (MSet None) else MGet) WithType.value (* WITHTYPETODO *) in
+	let mode = if set then (MSet None) else MGet in
+	let acc = type_access ctx (fst e) (snd e) mode WithType.value (* WITHTYPETODO *) in
 	let access e =
 		let make e =
 			let t = (match op with
@@ -1160,10 +1200,63 @@ and type_unop ctx op flag e p =
 		) with Not_found ->
 			make e
 	in
+	let handle_accessor etarget fa =
+		let emethod = FieldAccess.get_field_expr fa (if set then FRead else FWrite) in
+		let force_inline = fa.fa_inline in
+		let l = save_locals ctx in
+		let init_tmp,etarget,eget =
+			match needs_temp_var etarget, fst e with
+			| true, EField (_, field_name) ->
+				let tmp = gen_local ctx etarget.etype p in
+				let tmp_ident = (EConst (Ident tmp.v_name), p) in
+				(
+					mk (TVar (tmp, Some etarget)) ctx.t.tvoid p,
+					mk (TLocal tmp) tmp.v_type p,
+					(EField (tmp_ident,field_name), p)
+				)
+			| _ -> (mk (TBlock []) ctx.t.tvoid p, etarget, e)
+		in
+		let op = (match op with Increment -> OpAdd | Decrement -> OpSub | _ -> die "" __LOC__) in
+		let one = (EConst (Int "1"),p) in
+		(match follow emethod.etype with
+		| TFun (_, t) ->
+			(match flag with
+			| Prefix ->
+				let get = type_binop ctx op eget one false WithType.value p in
+				unify ctx get.etype t p;
+				l();
+				let call_setter = make_call ctx emethod [etarget; get] t ~force_inline p in
+				mk (TBlock [init_tmp; call_setter]) t p
+			| Postfix ->
+				let get = type_expr ctx eget WithType.value in
+				let tmp_value = gen_local ctx t p in
+				let plusone = type_binop ctx op (EConst (Ident tmp_value.v_name),p) one false WithType.value p in
+				unify ctx get.etype t p;
+				l();
+				mk (TBlock [
+					init_tmp;
+					mk (TVar (tmp_value,Some get)) ctx.t.tvoid p;
+					make_call ctx emethod [etarget; plusone] t ~force_inline p;
+					mk (TLocal tmp_value) t p;
+				]) t p
+			)
+		| _ ->
+			l();
+			die "" __LOC__
+		)
+	in
 	let rec loop acc =
 		match acc with
-		| AKExpr e -> access e
-		| AKInline _ | AKUsing _ when not set -> access (acc_get ctx acc p)
+		| AKExpr e ->
+			access e
+		| AKField fa ->
+			if fa.fa_inline && not set then
+				access (acc_get ctx acc p)
+			else begin
+				let e = FieldAccess.get_field_expr fa (if set then FWrite else FRead) in
+				access e
+			end
+		| AKUsingField _ | AKUsingAccessor _ when not set -> access (acc_get ctx acc p)
 		| AKNo s ->
 			error ("The field or identifier " ^ s ^ " is not accessible for " ^ (if set then "writing" else "reading")) p
 		| AKAccess(a,tl,c,ebase,ekey) ->
@@ -1188,53 +1281,28 @@ and type_unop ctx op flag e p =
 				let e = mk_array_get_call ctx (AbstractCast.find_array_access ctx a tl ekey None p) c ebase p in
 				loop (AKExpr e)
 			end
-		| AKUsing (emethod,cl,cf,etarget,force_inline) when (op = Decrement || op = Increment) && has_meta Meta.Impl cf.cf_meta ->
-			let l = save_locals ctx in
-			let init_tmp,etarget,eget =
-				match needs_temp_var etarget, fst e with
-				| true, EField (_, field_name) ->
-					let tmp = gen_local ctx etarget.etype p in
-					let tmp_ident = (EConst (Ident tmp.v_name), p) in
-					(
-						mk (TVar (tmp, Some etarget)) ctx.t.tvoid p,
-						mk (TLocal tmp) tmp.v_type p,
-						(EField (tmp_ident,field_name), p)
-					)
-				| _ -> (mk (TBlock []) ctx.t.tvoid p, etarget, e)
+		| AKUsingAccessor sea ->
+			let fa_set = match FieldAccess.resolve_accessor sea.se_access (MSet None) with
+				| AccessorFound fa -> fa
+				| _ -> error "Could not resolve accessor" p
 			in
-			let op = (match op with Increment -> OpAdd | Decrement -> OpSub | _ -> die "" __LOC__) in
-			let one = (EConst (Int "1"),p) in
-			(match follow cf.cf_type with
-			| TFun (_, t) ->
-				(match flag with
-				| Prefix ->
-					let get = type_binop ctx op eget one false WithType.value p in
-					unify ctx get.etype t p;
-					l();
-					let call_setter = make_call ctx emethod [etarget; get] t ~force_inline p in
-					mk (TBlock [init_tmp; call_setter]) t p
-				| Postfix ->
-					let get = type_expr ctx eget WithType.value in
-					let tmp_value = gen_local ctx t p in
-					let plusone = type_binop ctx op (EConst (Ident tmp_value.v_name),p) one false WithType.value p in
-					unify ctx get.etype t p;
-					l();
-					mk (TBlock [
-						init_tmp;
-						mk (TVar (tmp_value,Some get)) ctx.t.tvoid p;
-						make_call ctx emethod [etarget; plusone] t ~force_inline p;
-						mk (TLocal tmp_value) t p;
-					]) t p
-				)
-			| _ ->
-				l();
-				die "" __LOC__
-			)
-		| AKInline _ | AKUsing _ | AKMacro _ ->
+			handle_accessor sea.se_this fa_set
+		| AKUsingField sea when (op = Decrement || op = Increment) && has_meta Meta.Impl sea.se_access.fa_field.cf_meta ->
+			handle_accessor sea.se_this sea.se_access
+		| AKUsingField _ ->
 			error "This kind of operation is not supported" p
-		| AKFieldSet _ ->
-			error "Invalid operation" p
-		| AKSet (e,t,cf) ->
+		| AKResolve(sea,name) ->
+			if not set then
+				access ((new call_dispatcher ctx (MCall []) WithType.value p)#resolve_call sea name)
+			else
+				error "Invalid operation" p
+		| AKAccessor fa when not set ->
+			access ((new call_dispatcher ctx mode WithType.value p)#field_call fa [] [])
+		| AKAccessor fa ->
+			let e = fa.fa_on in
+			let ef = FieldAccess.get_field_expr fa FCall in
+			let t = ef.etype in
+			let cf = fa.fa_field in
 			let l = save_locals ctx in
 			let v = gen_local ctx e.etype p in
 			let ev = mk (TLocal v) e.etype p in
@@ -1329,17 +1397,17 @@ and handle_efield ctx e p0 mode with_type =
 			(* first, try to resolve the first ident in the chain and access its fields.
 			   this doesn't support untyped identifiers yet, because we want to check fully-qualified
 			   paths first (even in an untyped block) *)
-			field_chain ctx pnext (type_ident_raise ctx name p)
+			field_chain ctx pnext (type_ident_raise ctx name p MGet WithType.value)
 		with Not_found ->
 			(* first ident couldn't be resolved, it's probably a fully qualified path - resolve it *)
 			let path = (first :: pnext) in
 			try
-				resolve_dot_path ctx path
+				resolve_dot_path ctx path mode with_type
 			with Not_found ->
 				(* dot-path resolution failed, it could be an untyped field access that happens to look like a dot-path, e.g. `untyped __global__.String` *)
 				try
 					(* TODO: we don't really want to do full type_ident again, just the second part of it *)
-					field_chain ctx pnext (type_ident ctx name p)
+					field_chain ctx pnext (type_ident ctx name p MGet WithType.value)
 				with Error (Unknown_ident _,p2) as e when p = p2 ->
 					try
 						(* try raising a more sensible error if there was an uppercase-first (module name) part *)
@@ -1394,7 +1462,7 @@ and handle_efield ctx e p0 mode with_type =
 		| _ ->
 			(* non-ident expr occured: definitely NOT a fully-qualified access,
 			   resolve the field chain against this expression *)
-			let e = type_access ctx e p in
+			let e = type_access ctx e p MGet WithType.value in
 			field_chain ctx dot_path_acc e
 	in
 	loop [] (e,p0) mode with_type
@@ -1779,17 +1847,14 @@ and type_new ctx path el with_type force_inline p =
 			| _ -> fst path, p
 		end
 	in
-	let unify_constructor_call c params f ct = match follow ct with
-		| TFun (args,r) ->
-			(try
-				let fcc = unify_field_call ctx (FInstance(c,params,f)) el args r p false in
-				check_constructor_access ctx c fcc.fc_field p;
-				List.map fst fcc.fc_args
-			with Error (e,p) ->
-				display_error ctx (error_msg e) p;
-				[])
-		| _ ->
-			error "Constructor is not a function" p
+	let unify_constructor_call c fa =
+		(try
+			let fcc = unify_field_call ctx fa [] el p false in
+			check_constructor_access ctx c fcc.fc_field p;
+			List.map fst fcc.fc_args
+		with Error (e,p) ->
+			display_error ctx (error_msg e) p;
+			[])
 	in
 	let t = if (fst path).tparams <> [] then begin
 		try
@@ -1816,7 +1881,8 @@ and type_new ctx path el with_type force_inline p =
 			let monos = Monomorph.spawn_constrained_monos (fun t -> t) c.cl_params in
 			let ct, f = get_constructor ctx c monos p in
 			no_abstract_constructor c p;
-			ignore (unify_constructor_call c monos f ct);
+			let fa = FieldAccess.create (Builder.make_static_this c p) f (FHInstance(c,monos)) false p in
+			ignore (unify_constructor_call c fa);
 			begin try
 				Generic.build_generic ctx c p monos
 			with Generic.Generic_Exception _ as exc ->
@@ -1840,13 +1906,18 @@ and type_new ctx path el with_type force_inline p =
 	in
 	DisplayEmitter.check_display_type ctx t path;
 	let t = follow t in
-	let build_constructor_call c tl =
+	let build_constructor_call ao c tl =
 		let ct, f = get_constructor ctx c tl p in
 		no_abstract_constructor c p;
 		(match f.cf_kind with
 		| Var { v_read = AccRequire (r,msg) } -> (match msg with Some msg -> error msg p | None -> error_require r p)
 		| _ -> ());
-		let el = unify_constructor_call c tl f ct in
+		let fa = match ao with
+			| None -> FHInstance(c,tl)
+			| Some a -> FHAbstract(a,tl,c)
+		in
+		let fa = FieldAccess.create (Builder.make_static_this c p) f fa false p in
+		let el = unify_constructor_call c fa in
 		el,f,ct
 	in
 	try begin match t with
@@ -1860,13 +1931,13 @@ and type_new ctx path el with_type force_inline p =
 			mk (TNew (c,params,el)) t p
 		end
 	| TAbstract({a_impl = Some c} as a,tl) when not (Meta.has Meta.MultiType a.a_meta) ->
-		let el,cf,ct = build_constructor_call c tl in
+		let el,cf,ct = build_constructor_call (Some a) c tl in
 		let ta = mk_anon ~fields:c.cl_statics (ref (Statics c)) in
 		let e = mk (TTypeExpr (TClassDecl c)) ta p in
 		let e = mk (TField (e,(FStatic (c,cf)))) ct p in
 		make_call ctx e el t ~force_inline p
 	| TInst (c,params) | TAbstract({a_impl = Some c},params) ->
-		let el,_,_ = build_constructor_call c params in
+		let el,_,_ = build_constructor_call None c params in
 		mk (TNew (c,params,el)) t p
 	| _ ->
 		error (s_type (print_context()) t ^ " cannot be constructed") p
@@ -2408,16 +2479,12 @@ and type_call_target ctx e el with_type inline p =
 	if not inline then
 		e
 	else match e with
-		| AKExpr {eexpr = TField(e1,fa); etype = t} ->
-			begin match extract_field fa with
-			| Some cf ->
-				check_inline cf;
-				AKInline(e1,cf,fa,t)
-			| None -> e
-			end;
-		| AKUsing(e,c,cf,ef,_) ->
-			check_inline cf;
-			AKUsing(e,c,cf,ef,true)
+		| AKField fa ->
+			check_inline fa.fa_field;
+			AKField({fa with fa_inline = true})
+		| AKUsingField sea ->
+			check_inline sea.se_access.fa_field;
+			AKUsingField {sea with se_access = {sea.se_access with fa_inline = true}}
 		| AKExpr {eexpr = TLocal _} ->
 			display_error ctx "Cannot force inline on local functions" p;
 			e
@@ -2497,15 +2564,13 @@ and type_call ?(mode=MGet) ctx e el (with_type:WithType.t) inline p =
 		| None -> error "Current class does not have a super" p
 		| Some (c,params) ->
 			let ct, f = get_constructor ctx c params p in
+			let t = TInst (c,params) in
+			let e = mk (TConst TSuper) t sp in
 			if (Meta.has Meta.CompilerGenerated f.cf_meta) then display_error ctx (error_msg (No_constructor (TClassDecl c))) p;
-			let el = (match follow ct with
-			| TFun (args,r) ->
-				let fcc = unify_field_call ctx (FInstance(c,params,f)) el args r p false in
-				List.map fst fcc.fc_args
-			| _ ->
-				error "Constructor is not a function" p
-			) in
-			el , TInst (c,params)
+			let fa = FieldAccess.create e f (FHInstance(c,params)) false p in
+			let fcc = unify_field_call ctx fa [] el p false in
+			let el = List.map fst fcc.fc_args in
+			el,t
 		) in
 		mk (TCall (mk (TConst TSuper) t sp,el)) ctx.t.tvoid p
 	| _ ->

+ 179 - 15
src/typing/typerBase.ml

@@ -4,15 +4,34 @@ open Type
 open Typecore
 open Error
 
+type field_host =
+	| FHStatic of tclass
+	| FHInstance of tclass * tparams
+	| FHAbstract of tabstract * tparams * tclass
+	| FHAnon
+
+type field_access = {
+	fa_on : texpr;
+	fa_field : tclass_field;
+	fa_host : field_host;
+	fa_inline : bool;
+	fa_pos : pos;
+}
+
+type static_extension_access = {
+	se_this : texpr;
+	se_access : field_access;
+}
+
 type access_kind =
 	| AKNo of string
 	| AKExpr of texpr
-	| AKSet of texpr * t * tclass_field
-	| AKInline of texpr * tclass_field * tfield_access * t
-	| AKMacro of texpr * tclass_field
-	| AKUsing of texpr * tclass * tclass_field * texpr * bool (* forced inline *)
+	| AKField of field_access
+	| AKAccessor of field_access (* fa_field is the property, not the accessor *)
+	| AKUsingField of static_extension_access
+	| AKUsingAccessor of static_extension_access
 	| AKAccess of tabstract * tparams * tclass * texpr * texpr
-	| AKFieldSet of texpr * texpr * string * t
+	| AKResolve of static_extension_access * string
 
 type object_decl_kind =
 	| ODKWithStructure of tanon
@@ -143,23 +162,43 @@ let rec type_module_type ctx t tparams p =
 let type_type ctx tpath p =
 	type_module_type ctx (Typeload.load_type_def ctx p (mk_type_path tpath)) None p
 
-let mk_module_type_access ctx t p : access_mode -> WithType.t -> access_kind =
-	let e = type_module_type ctx t None p in
-	(fun _ _ -> AKExpr e)
+let mk_module_type_access ctx t p =
+	AKExpr (type_module_type ctx t None p)
+
+let s_field_access tabs fa =
+	let st = s_type (print_context()) in
+	let se = s_expr_pretty true "" false st in
+	let sfa = function
+		| FHStatic c -> Printf.sprintf "FHStatic(%s)" (s_type_path c.cl_path)
+		| FHInstance(c,tl) -> Printf.sprintf "FHInstance(%s, %s)" (s_type_path c.cl_path) (s_types tl)
+		| FHAbstract(a,tl,c) -> Printf.sprintf "FHAbstract(%s, %s, %s)" (s_type_path a.a_path) (s_types tl) (s_type_path c.cl_path)
+		| FHAnon -> Printf.sprintf "FHAnon"
+	in
+	Printer.s_record_fields tabs [
+		"fa_on",se fa.fa_on;
+		"fa_field",fa.fa_field.cf_name;
+		"fa_host",sfa fa.fa_host;
+		"fa_inline",string_of_bool fa.fa_inline
+	]
+
+let s_static_extension_access sea =
+	Printer.s_record_fields "" [
+		"se_this",s_expr_pretty true "" false (s_type (print_context())) sea.se_this;
+		"se_access",s_field_access "\t" sea.se_access
+	]
 
 let s_access_kind acc =
 	let st = s_type (print_context()) in
 	let se = s_expr_pretty true "" false st in
-	let sfa = s_field_access st in
 	match acc with
 	| AKNo s -> "AKNo " ^ s
 	| AKExpr e -> "AKExpr " ^ (se e)
-	| AKSet(e,t,cf) -> Printf.sprintf "AKSet(%s, %s, %s)" (se e) (st t) cf.cf_name
-	| AKInline(e,cf,fa,t) -> Printf.sprintf "AKInline(%s, %s, %s, %s)" (se e) cf.cf_name (sfa fa) (st t)
-	| AKMacro(e,cf) -> Printf.sprintf "AKMacro(%s, %s)" (se e) cf.cf_name
-	| AKUsing(e1,c,cf,e2,b) -> Printf.sprintf "AKUsing(%s, %s, %s, %s, %b)" (se e1) (s_type_path c.cl_path) cf.cf_name (se e2) b
+	| AKField fa -> Printf.sprintf "AKField(%s)" (s_field_access "" fa)
+	| AKAccessor fa -> Printf.sprintf "AKAccessor(%s)" (s_field_access "" fa)
+	| AKUsingField sea -> Printf.sprintf "AKUsingField(%s)" (s_static_extension_access sea)
+	| AKUsingAccessor sea -> Printf.sprintf "AKUsingAccessor(%s)" (s_static_extension_access sea)
 	| AKAccess(a,tl,c,e1,e2) -> Printf.sprintf "AKAccess(%s, [%s], %s, %s, %s)" (s_type_path a.a_path) (String.concat ", " (List.map st tl)) (s_type_path c.cl_path) (se e1) (se e2)
-	| AKFieldSet(_) -> ""
+	| AKResolve(_) -> ""
 
 let get_constructible_constraint ctx tl p =
 	let extract_function t = match follow t with
@@ -216,4 +255,129 @@ let get_abstract_froms a pl =
 				acc)
 		| _ ->
 			acc
-	) l a.a_from_field
+	) l a.a_from_field
+
+module FieldAccess = struct
+	type field_host =
+		| FGet (* get the plain expression with applied field type parameters *)
+		| FCall (* does not apply field type parameters *)
+		| FRead (* actual reading, for FClosure and such *)
+		| FWrite (* used as lhs, no semantic difference to FGet *)
+
+	type accessor_resolution =
+		| AccessorFound of field_access
+		| AccessorAnon
+		| AccessorNotFound
+		| AccessorInvalid
+
+	let create e cf fh inline p = {
+		fa_on = e;
+		fa_field = cf;
+		fa_host = fh;
+		fa_inline = inline;
+		fa_pos = p;
+	}
+
+	let apply_fa cf = function
+		| FHStatic c -> FStatic(c,cf)
+		| FHInstance(c,tl) -> FInstance(c,tl,cf)
+		| FHAbstract(a,tl,c) -> FStatic(c,cf)
+		| FHAnon -> FAnon cf
+
+	let get_map_function fa = match fa.fa_host with
+		| FHStatic _ | FHAnon -> (fun t -> t)
+		| FHInstance(c,tl) -> TClass.get_map_function c tl
+		| FHAbstract(a,tl,_) -> apply_params a.a_params tl
+
+	let get_field_expr fa mode =
+		let cf = fa.fa_field in
+		let t = match mode with
+			| FCall -> cf.cf_type
+			| FGet | FRead | FWrite -> Type.field_type cf
+		in
+		let fa',t = match fa.fa_host with
+			| FHStatic c ->
+				FStatic(c,cf),t
+			| FHInstance(c,tl) ->
+				let fa = match cf.cf_kind with
+				| Method _ when mode = FRead ->
+					FClosure(Some(c,tl),cf)
+				| _ ->
+					FInstance(c,tl,cf)
+				in
+				let t = TClass.get_map_function c tl t in
+				fa,t
+			| FHAbstract(a,tl,c) ->
+				FStatic(c,cf),apply_params a.a_params tl t
+			| FHAnon ->
+				let fa = match cf.cf_kind with
+				| Method _ when mode = FRead ->
+					FClosure(None,cf)
+				| _ ->
+					FAnon cf
+				in
+				fa,t
+		in
+		mk (TField(fa.fa_on,fa')) t fa.fa_pos
+
+	let resolve_accessor fa mode = match fa.fa_field.cf_kind with
+		| Var v ->
+			begin match (match mode with MSet _ -> v.v_write | _ -> v.v_read) with
+				| AccCall ->
+					let name = (match mode with MSet _ -> "set_" | _ -> "get_") ^ fa.fa_field.cf_name in
+					let forward cf_acc new_host =
+						create fa.fa_on cf_acc new_host fa.fa_inline fa.fa_pos
+					in
+					begin match fa.fa_host with
+					| FHStatic c ->
+						begin try
+							AccessorFound (forward (PMap.find name c.cl_statics) fa.fa_host)
+						with Not_found ->
+							(* TODO: Check if this is correct, there's a case in hxcpp's VirtualArray *)
+							AccessorAnon
+						end
+					| FHInstance(c,tl) ->
+						begin try
+							(* Accessors can be overridden, so we have to check the actual type. *)
+							let c,tl = match follow fa.fa_on.etype with
+								| TInst(c,tl) -> c,tl
+								| _ -> c,tl
+							in
+							let (c2,_,cf_acc) = raw_class_field (fun f -> f.cf_type) c tl name in
+							let new_host = match c2 with
+								| None -> FHAnon
+								| Some(c,tl) -> FHInstance(c,tl)
+							in
+							AccessorFound (forward cf_acc new_host)
+						with Not_found ->
+							AccessorAnon
+						end
+					| FHAbstract(a,tl,c) ->
+						begin try
+							AccessorFound (forward (PMap.find name c.cl_statics) fa.fa_host)
+						with Not_found ->
+							AccessorAnon
+						end
+					| FHAnon ->
+						AccessorAnon
+					end
+				| _ ->
+					AccessorInvalid
+			end
+		| _ ->
+			AccessorInvalid
+end
+
+let make_static_extension_access c cf e_this inline p =
+	let e_static = Texpr.Builder.make_static_this c p in
+	{
+		se_this = e_this;
+		se_access = FieldAccess.create e_static cf (FHStatic c) inline p
+	}
+
+let make_abstract_static_extension_access a tl c cf e_this inline p =
+	let e_static = Texpr.Builder.make_static_this c p in
+	{
+		se_this = e_this;
+		se_access = FieldAccess.create e_static cf (FHAbstract(a,tl,c)) inline p
+	}

+ 18 - 21
src/typing/typerDotPath.ml

@@ -40,25 +40,23 @@ let s_dot_path parts =
 	String.concat "." (List.map (fun (s,_,_) -> s) parts)
 
 (** resolve given path against module fields or raise Not_found *)
-let resolve_module_field ctx m path p =
+let resolve_module_field ctx m path p mode with_type =
 	match path, m.m_statics with
 	| [], _ | _, None ->
 		raise Not_found
 	| (name,_,p) :: path_rest, Some c ->
 		let f = PMap.find name c.cl_statics in (* raises Not_found *)
-		check_field_access ctx c f true p;
-		let ft = Fields.field_type ctx c [] f p in
 		let e = type_module_type ctx (TClassDecl c) None p in
-		(fun mode _ (* WITHTYPETODO *) -> field_access ctx mode f (FStatic (c,f)) ft e p), path_rest
+		field_access ctx mode f (FHStatic c) e p, path_rest
 
 let resolve_module_type ctx m name p =
 	let t = Typeload.find_type_in_module m name in (* raises Not_found *)
 	mk_module_type_access ctx t p
 
-let resolve_in_module ctx m path p =
+let resolve_in_module ctx m path p mode with_type =
 	try
 		(* first, try to find module-level static access *)
-		resolve_module_field ctx m path p
+		resolve_module_field ctx m path p mode with_type
 	with Not_found ->
 		(* if there was no module fields, resolve  *)
 		let mname = snd m.m_path in
@@ -74,10 +72,10 @@ let resolve_in_module ctx m path p =
 			resolve_module_type ctx m mname p, path
 
 (** resolve given qualified module pack+name (and possibly next path part) or raise Not_found *)
-let resolve_qualified ctx pack name next_path p =
+let resolve_qualified ctx pack name next_path p mode with_type =
 	try
 		let m = Typeload.load_module ctx (pack,name) p in
-		resolve_in_module ctx m next_path p
+		resolve_in_module ctx m next_path p mode with_type
 	with Error (Module_not_found mpath,_) when mpath = (pack,name) ->
 		(* might be an instance of https://github.com/HaxeFoundation/haxe/issues/9150
 		   so let's also check (pack,name) of a TYPE in the current module context ¯\_(ツ)_/¯ *)
@@ -85,7 +83,7 @@ let resolve_qualified ctx pack name next_path p =
 		mk_module_type_access ctx t p, next_path
 
 (** resolve the given unqualified name (and possibly next path part) or raise Not_found *)
-let resolve_unqualified ctx name next_path p =
+let resolve_unqualified ctx name next_path p mode with_type =
 	try
 		(* if there's a type with this name in current module context - try resolving against it *)
 		let t = Typeload.find_type_in_current_module_context ctx [] name in (* raises Not_found *)
@@ -98,24 +96,18 @@ let resolve_unqualified ctx name next_path p =
 			match next_path with
 			| (field,_,pfield) :: next_path ->
 				let e = type_module_type ctx t None p in
-				let f = type_field (TypeFieldConfig.create true) ctx e field pfield in
-				begin (* huge hack around #9430: we need Not_found, but we don't want any errors *)
-					let old_on_error = ctx.on_error in
-					ctx.on_error <- (fun _ _ _ -> ());
-					(* raises Not_found *) (* not necessarily a call, but prevent #2602 among others *)
-					ignore (Std.finally (fun () -> ctx.on_error <- old_on_error) (f (MCall [])) WithType.value)
-				end; (* huge hack *)
-				f, next_path
+				let access = type_field (TypeFieldConfig.create true) ctx e field pfield mode with_type in
+				access, next_path
 			| _ ->
 				mk_module_type_access ctx t p, next_path
 		end
 	with Not_found ->
 		(* otherwise run the unqualified module resolution mechanism and look into the modules  *)
-		let f m ~resume = resolve_in_module ctx m next_path p in
+		let f m ~resume = resolve_in_module ctx m next_path p mode with_type in
 		Typeload.find_in_unqualified_modules ctx name p f ~resume:true (* raise Not_found *)
 
 (** given a list of dot path parts, resolve it into access getter or raise Not_found *)
-let resolve_dot_path ctx (path_parts : dot_path_part list) =
+let resolve_dot_path ctx (path_parts : dot_path_part list) mode with_type =
 	let rec loop pack_acc path =
 		match path with
 		| (_,PLowercase,_) as x :: path ->
@@ -123,13 +115,18 @@ let resolve_dot_path ctx (path_parts : dot_path_part list) =
 			loop (x :: pack_acc) path
 
 		| (name,PUppercase,p) :: path ->
+			(* If this is the last part we want to use the actual mode. *)
+			let mode,with_type = match path with
+				| [] | [_] -> mode,with_type
+				| _ -> MGet,WithType.value
+			in
 			(* part starts with uppercase - it's a module name - try resolving *)
 			let accessor, path_rest =
 				if pack_acc <> [] then
 					let pack = List.rev_map (fun (x,_,_) -> x) pack_acc in
-					resolve_qualified ctx pack name path p
+					resolve_qualified ctx pack name path p mode with_type
 				else
-					resolve_unqualified ctx name path p
+					resolve_unqualified ctx name path p mode with_type
 			in
 			(* if we get here (that is, Not_found is not raised) - we have something to resolve against *)
 			field_chain ctx path_rest accessor

+ 1 - 1
std/flash/Boot.hx

@@ -58,7 +58,7 @@ class Boot extends flash.display.MovieClip {
 		var c = flash.Lib.current;
 		try {
 			untyped if (c == this && c.stage != null && c.stage.align == "")
-				c.stage.align = "TOP_LEFT";
+				c.stage.align = cast "TOP_LEFT";
 		} catch (e:Dynamic) {
 			// security error when loading from different domain
 		}

+ 1 - 0
tests/misc/projects/Issue5940/compile-fail.hxml.stderr

@@ -1 +1,2 @@
 Main.hx:3: characters 21-24 : Cannot access non-static abstract field statically
+Main.hx:3: characters 15-24 : Not enough arguments, expected this:Int