Browse Source

[display] move field completion collect method into a separate module

Dan Korostelev 7 years ago
parent
commit
9d94c84c81
4 changed files with 292 additions and 267 deletions
  1. 197 0
      src/context/displayFields.ml
  2. 91 0
      src/context/typecore.ml
  3. 1 1
      src/typing/matcher.ml
  4. 3 266
      src/typing/typer.ml

+ 197 - 0
src/context/displayFields.ml

@@ -0,0 +1,197 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2017  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*)
+open Ast
+open Globals
+open Error
+open Typecore
+open Type
+
+let get_submodule_fields ctx path =
+	let m = Hashtbl.find ctx.g.modules path in
+	let tl = List.filter (fun t -> path <> (t_infos t).mt_path && not (t_infos t).mt_private) m.m_types in
+	let tl = List.map (fun mt ->
+		let infos = t_infos mt in
+		(snd infos.mt_path),Display.FKType (type_of_module_type mt),infos.mt_doc
+	) tl in
+	tl
+
+let collect ctx e_ast e with_type p =
+	let merge_core_doc = !merge_core_doc_ref in
+	let opt_args args ret = TFun(List.map(fun (n,o,t) -> n,true,t) args,ret) in
+	let e = match e.eexpr with
+		| TField (e1,fa) ->
+			if field_name fa = "bind" then (match follow e1.etype with
+				| TFun(args,ret) -> {e1 with etype = opt_args args ret}
+				| _ -> e)
+			else
+				e
+		| _ ->
+			e
+	in
+	let opt_type t =
+		match t with
+		| TLazy f ->
+			Typeload.return_partial_type := true;
+			let t = lazy_type f in
+			Typeload.return_partial_type := false;
+			t
+		| _ ->
+			t
+	in
+	let should_access c cf stat =
+		if c != ctx.curclass && not cf.cf_public && String.length cf.cf_name > 4 then begin match String.sub cf.cf_name 0 4 with
+			| "get_" | "set_" -> false
+			| _ -> can_access ctx c cf stat
+		end else
+			can_access ctx c cf stat
+	in
+	let rec get_fields t =
+		match follow t with
+		| TInst (c,params) ->
+			if Meta.has Meta.CoreApi c.cl_meta then merge_core_doc ctx c;
+			let merge ?(cond=(fun _ -> true)) a b =
+				PMap.foldi (fun k f m -> if cond f then PMap.add k f m else m) a b
+			in
+			let rec loop c params =
+				let m = List.fold_left (fun m (i,params) ->
+					merge m (loop i params)
+				) PMap.empty c.cl_implements in
+				let m = (match c.cl_super with
+					| None -> m
+					| Some (csup,cparams) -> merge m (loop csup cparams)
+				) in
+				let m = merge ~cond:(fun f -> should_access c f false) c.cl_fields m in
+				let m = (match c.cl_kind with
+					| KTypeParameter pl -> List.fold_left (fun acc t -> merge acc (get_fields t)) m pl
+					| _ -> m
+				) in
+				PMap.map (fun f -> { f with cf_type = apply_params c.cl_params params (opt_type f.cf_type); cf_public = true; }) m
+			in
+			loop c params
+		| TAbstract({a_impl = Some c} as a,pl) ->
+			if Meta.has Meta.CoreApi c.cl_meta then merge_core_doc ctx c;
+			let fields = try
+				let _,el,_ = Meta.get Meta.Forward a.a_meta in
+				let sl = ExtList.List.filter_map (fun e -> match fst e with
+					| EConst(Ident s) -> Some s
+					| _ -> None
+				) el in
+				let fields = get_fields (apply_params a.a_params pl a.a_this) in
+				if sl = [] then fields else PMap.fold (fun cf acc ->
+					if List.mem cf.cf_name sl then
+						PMap.add cf.cf_name cf acc
+					else
+						acc
+				) fields PMap.empty
+			with Not_found ->
+				PMap.empty
+			in
+			PMap.fold (fun f acc ->
+				if f.cf_name <> "_new" && should_access c f true && Meta.has Meta.Impl f.cf_meta && not (Meta.has Meta.Enum f.cf_meta) then begin
+					let f = prepare_using_field f in
+					let t = apply_params a.a_params pl (follow f.cf_type) in
+					PMap.add f.cf_name { f with cf_public = true; cf_type = opt_type t } acc
+				end else
+					acc
+			) c.cl_statics fields
+		| TAnon a when PMap.is_empty a.a_fields ->
+			begin match with_type with
+			| WithType t -> get_fields t
+			| _ -> a.a_fields
+			end
+		| TAnon a ->
+			(match !(a.a_status) with
+			| Statics c ->
+				if Meta.has Meta.CoreApi c.cl_meta then merge_core_doc ctx c;
+				let is_abstract_impl = match c.cl_kind with KAbstractImpl _ -> true | _ -> false in
+				let pm = match c.cl_constructor with None -> PMap.empty | Some cf -> PMap.add "new" cf PMap.empty in
+				PMap.fold (fun f acc ->
+					if should_access c f true && (not is_abstract_impl || not (Meta.has Meta.Impl f.cf_meta) || Meta.has Meta.Enum f.cf_meta) then
+						PMap.add f.cf_name { f with cf_public = true; cf_type = opt_type f.cf_type } acc else acc
+				) a.a_fields pm
+			| _ ->
+				a.a_fields)
+		| TFun (args,ret) ->
+			let t = opt_args args ret in
+			let cf = mk_field "bind" (tfun [t] t) p null_pos in
+			cf.cf_kind <- Method MethNormal;
+			PMap.add "bind" cf PMap.empty
+		| _ ->
+			PMap.empty
+	in
+	let fields = get_fields e.etype in
+	(*
+		add 'using' methods compatible with this type
+	*)
+	let rec loop acc = function
+		| [] -> acc
+		| (c,_) :: l ->
+			let acc = ref (loop acc l) in
+			let rec dup t = Type.map dup t in
+			List.iter (fun f ->
+				if not (Meta.has Meta.NoUsing f.cf_meta) && not (Meta.has Meta.Impl f.cf_meta) then
+				let f = { f with cf_type = opt_type f.cf_type } in
+				let monos = List.map (fun _ -> mk_mono()) f.cf_params in
+				let map = apply_params f.cf_params monos in
+				match follow (map f.cf_type) with
+				| TFun((_,_,TType({t_path=["haxe";"macro"], "ExprOf"}, [t])) :: args, ret)
+				| TFun((_,_,t) :: args, ret) ->
+					(try
+						unify_raise ctx (dup e.etype) t e.epos;
+						List.iter2 (fun m (name,t) -> match follow t with
+							| TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
+								List.iter (fun tc -> unify_raise ctx m (map tc) e.epos) constr
+							| _ -> ()
+						) monos f.cf_params;
+						if not (can_access ctx c f true) || follow e.etype == t_dynamic && follow t != t_dynamic then
+							()
+						else begin
+							let f = prepare_using_field f in
+							let f = { f with cf_params = []; cf_public = true; cf_type = TFun(args,ret) } in
+							acc := PMap.add f.cf_name f (!acc)
+						end
+					with Error (Unify _,_) -> ())
+				| _ -> ()
+			) c.cl_ordered_statics;
+			!acc
+	in
+	let use_methods = match follow e.etype with TMono _ -> PMap.empty | _ -> loop (loop PMap.empty ctx.g.global_using) ctx.m.module_using in
+	let fields = PMap.fold (fun f acc -> PMap.add f.cf_name f acc) fields use_methods in
+	let fields = match fst e_ast with
+		| EConst(String s) when String.length s = 1 ->
+			let cf = mk_field "code" ctx.t.tint e.epos null_pos in
+			cf.cf_doc <- Some "The character code of this character (inlined at compile-time).";
+			cf.cf_kind <- Var { v_read = AccNormal; v_write = AccNever };
+			PMap.add cf.cf_name cf fields
+		| _ ->
+			fields
+	in
+	let fields = PMap.fold (fun f acc -> if Meta.has Meta.NoCompletion f.cf_meta then acc else f :: acc) fields [] in
+	let get_field acc f =
+		List.fold_left (fun acc f ->
+			let kind = match f.cf_kind with Method _ -> Display.FKMethod f.cf_type | Var _ -> Display.FKVar f.cf_type in
+			if f.cf_public then (f.cf_name,kind,f.cf_doc) :: acc else acc
+		) acc (f :: f.cf_overloads)
+	in
+	let fields = List.fold_left get_field [] fields in
+	try
+		let sl = string_list_of_expr_path_raise e_ast in
+		fields @ get_submodule_fields ctx (List.tl sl,List.hd sl)
+	with Exit | Not_found ->
+		fields

+ 91 - 0
src/context/typecore.ml

@@ -321,6 +321,97 @@ let is_removable_field ctx f =
 		| Method MethMacro -> not ctx.in_macro
 		| _ -> false)
 
+(** checks if we can access to a given class field using current context *)
+let rec can_access ctx ?(in_overload=false) c cf stat =
+	if cf.cf_public then
+		true
+	else if not in_overload && ctx.com.config.pf_overload && Meta.has Meta.Overload cf.cf_meta then
+		true
+	else
+	(* TODO: should we add a c == ctx.curclass short check here? *)
+	(* has metadata path *)
+	let rec make_path c f = match c.cl_kind with
+		| KAbstractImpl a -> fst a.a_path @ [snd a.a_path; f.cf_name]
+		| KGenericInstance(c,_) -> make_path c f
+		| _ when c.cl_private -> List.rev (f.cf_name :: snd c.cl_path :: (List.tl (List.rev (fst c.cl_path))))
+		| _ -> fst c.cl_path @ [snd c.cl_path; f.cf_name]
+	in
+	let rec expr_path acc e =
+		match fst e with
+		| EField (e,f) -> expr_path (f :: acc) e
+		| EConst (Ident n) -> n :: acc
+		| _ -> []
+	in
+	let rec chk_path psub pfull =
+		match psub, pfull with
+		| [], _ -> true
+		| a :: l1, b :: l2 when a = b -> chk_path l1 l2
+		| _ -> false
+	in
+	let has m c f path =
+		let rec loop = function
+			| (m2,el,_) :: l when m = m2 ->
+				List.exists (fun e ->
+					let p = expr_path [] e in
+					(p <> [] && chk_path p path)
+				) el
+				|| loop l
+			| _ :: l -> loop l
+			| [] -> false
+		in
+		loop c.cl_meta || loop f.cf_meta
+	in
+	let cur_paths = ref [] in
+	let rec loop c =
+		cur_paths := make_path c ctx.curfield :: !cur_paths;
+		begin match c.cl_super with
+			| Some (csup,_) -> loop csup
+			| None -> ()
+		end;
+		List.iter (fun (c,_) -> loop c) c.cl_implements;
+	in
+	loop ctx.curclass;
+	let is_constr = cf.cf_name = "new" in
+	let rec loop c =
+		(try
+			(* if our common ancestor declare/override the field, then we can access it *)
+			let f = if is_constr then (match c.cl_constructor with None -> raise Not_found | Some c -> c) else PMap.find cf.cf_name (if stat then c.cl_statics else c.cl_fields) in
+			is_parent c ctx.curclass || (List.exists (has Meta.Allow c f) !cur_paths)
+		with Not_found ->
+			false
+		)
+		|| (match c.cl_super with
+		| Some (csup,_) -> loop csup
+		| None -> false)
+		|| has Meta.Access ctx.curclass ctx.curfield (make_path c cf)
+	in
+	let b = loop c
+	(* access is also allowed of we access a type parameter which is constrained to our (base) class *)
+	|| (match c.cl_kind with
+		| KTypeParameter tl ->
+			List.exists (fun t -> match follow t with TInst(c,_) -> loop c | _ -> false) tl
+		| _ -> false)
+	|| (Meta.has Meta.PrivateAccess ctx.meta) in
+	(* TODO: find out what this does and move it to genas3 *)
+	if b && Common.defined ctx.com Common.Define.As3 && not (Meta.has Meta.Public cf.cf_meta) then cf.cf_meta <- (Meta.Public,[],cf.cf_pos) :: cf.cf_meta;
+	b
+
+(** removes the first argument of the class field's function type and all its overloads *)
+let prepare_using_field cf = match follow cf.cf_type with
+	| TFun((_,_,tf) :: args,ret) ->
+		let rec loop acc overloads = match overloads with
+			| ({cf_type = TFun((_,_,tfo) :: args,ret)} as cfo) :: l ->
+				let tfo = apply_params cfo.cf_params (List.map snd cfo.cf_params) tfo in
+				(* ignore overloads which have a different first argument *)
+				if type_iseq tf tfo then loop ({cfo with cf_type = TFun(args,ret)} :: acc) l else loop acc l
+			| _ :: l ->
+				loop acc l
+			| [] ->
+				acc
+		in
+		{cf with cf_overloads = loop [] cf.cf_overloads; cf_type = TFun(args,ret)}
+	| _ -> cf
+
 (* -------------------------------------------------------------------------- *)
 (* ABSTRACT CASTS *)
 

+ 1 - 1
src/typing/matcher.ml

@@ -384,7 +384,7 @@ module Pattern = struct
 					| TInst(c,tl) ->
 						let rec loop fields c tl =
 							let fields = List.fold_left (fun acc cf ->
-								if Typer.can_access ctx c cf false then (cf,apply_params c.cl_params tl cf.cf_type) :: acc
+								if Typecore.can_access ctx c cf false then (cf,apply_params c.cl_params tl cf.cf_type) :: acc
 								else acc
 							) fields c.cl_ordered_fields in
 							match c.cl_super with

+ 3 - 266
src/typing/typer.ml

@@ -15,8 +15,7 @@
 	You should have received a copy of the GNU General Public License
 	along with this program; if not, write to the Free Software
 	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *)
-
+*)
 open Ast
 open Common.DisplayMode
 open Common
@@ -258,97 +257,6 @@ let field_type ctx c pl f p =
 let class_field ctx c tl name p =
 	raw_class_field (fun f -> field_type ctx c tl f p) c tl name
 
-(* checks if we can access to a given class field using current context *)
-let rec can_access ctx ?(in_overload=false) c cf stat =
-	if cf.cf_public then
-		true
-	else if not in_overload && ctx.com.config.pf_overload && Meta.has Meta.Overload cf.cf_meta then
-		true
-	else
-	(* TODO: should we add a c == ctx.curclass short check here? *)
-	(* has metadata path *)
-	let rec make_path c f = match c.cl_kind with
-		| KAbstractImpl a -> fst a.a_path @ [snd a.a_path; f.cf_name]
-		| KGenericInstance(c,_) -> make_path c f
-		| _ when c.cl_private -> List.rev (f.cf_name :: snd c.cl_path :: (List.tl (List.rev (fst c.cl_path))))
-		| _ -> fst c.cl_path @ [snd c.cl_path; f.cf_name]
-	in
-	let rec expr_path acc e =
-		match fst e with
-		| EField (e,f) -> expr_path (f :: acc) e
-		| EConst (Ident n) -> n :: acc
-		| _ -> []
-	in
-	let rec chk_path psub pfull =
-		match psub, pfull with
-		| [], _ -> true
-		| a :: l1, b :: l2 when a = b -> chk_path l1 l2
-		| _ -> false
-	in
-	let has m c f path =
-		let rec loop = function
-			| (m2,el,_) :: l when m = m2 ->
-				List.exists (fun e ->
-					let p = expr_path [] e in
-					(p <> [] && chk_path p path)
-				) el
-				|| loop l
-			| _ :: l -> loop l
-			| [] -> false
-		in
-		loop c.cl_meta || loop f.cf_meta
-	in
-	let cur_paths = ref [] in
-	let rec loop c =
-		cur_paths := make_path c ctx.curfield :: !cur_paths;
-		begin match c.cl_super with
-			| Some (csup,_) -> loop csup
-			| None -> ()
-		end;
-		List.iter (fun (c,_) -> loop c) c.cl_implements;
-	in
-	loop ctx.curclass;
-	let is_constr = cf.cf_name = "new" in
-	let rec loop c =
-		(try
-			(* if our common ancestor declare/override the field, then we can access it *)
-			let f = if is_constr then (match c.cl_constructor with None -> raise Not_found | Some c -> c) else PMap.find cf.cf_name (if stat then c.cl_statics else c.cl_fields) in
-			is_parent c ctx.curclass || (List.exists (has Meta.Allow c f) !cur_paths)
-		with Not_found ->
-			false
-		)
-		|| (match c.cl_super with
-		| Some (csup,_) -> loop csup
-		| None -> false)
-		|| has Meta.Access ctx.curclass ctx.curfield (make_path c cf)
-	in
-	let b = loop c
-	(* access is also allowed of we access a type parameter which is constrained to our (base) class *)
-	|| (match c.cl_kind with
-		| KTypeParameter tl ->
-			List.exists (fun t -> match follow t with TInst(c,_) -> loop c | _ -> false) tl
-		| _ -> false)
-	|| (Meta.has Meta.PrivateAccess ctx.meta) in
-	(* TODO: find out what this does and move it to genas3 *)
-	if b && Common.defined ctx.com Common.Define.As3 && not (Meta.has Meta.Public cf.cf_meta) then cf.cf_meta <- (Meta.Public,[],cf.cf_pos) :: cf.cf_meta;
-	b
-
-(* removes the first argument of the class field's function type and all its overloads *)
-let prepare_using_field cf = match follow cf.cf_type with
-	| TFun((_,_,tf) :: args,ret) ->
-		let rec loop acc overloads = match overloads with
-			| ({cf_type = TFun((_,_,tfo) :: args,ret)} as cfo) :: l ->
-				let tfo = apply_params cfo.cf_params (List.map snd cfo.cf_params) tfo in
-				(* ignore overloads which have a different first argument *)
-				if Type.type_iseq tf tfo then loop ({cfo with cf_type = TFun(args,ret)} :: acc) l else loop acc l
-			| _ :: l ->
-				loop acc l
-			| [] ->
-				acc
-		in
-		{cf with cf_overloads = loop [] cf.cf_overloads; cf_type = TFun(args,ret)}
-	| _ -> cf
-
 let merge_core_doc ctx c =
 	let c_core = Typeload.load_core_class ctx c in
 	if c.cl_doc = None then c.cl_doc <- c_core.cl_doc;
@@ -3673,15 +3581,6 @@ and type_expr ctx (e,p) (with_type:with_type) =
 		ctx.meta <- old;
 		e
 
-and get_submodule_fields ctx path =
-	let m = Hashtbl.find ctx.g.modules path in
-	let tl = List.filter (fun t -> path <> (t_infos t).mt_path && not (t_infos t).mt_private) m.m_types in
-	let tl = List.map (fun mt ->
-		let infos = t_infos mt in
-		(snd infos.mt_path),Display.FKType (type_of_module_type mt),infos.mt_doc
-	) tl in
-	tl
-
 and handle_display ctx e_ast with_type =
 	let old = ctx.in_display,ctx.in_call_args in
 	ctx.in_display <- true;
@@ -3700,7 +3599,7 @@ and handle_display ctx e_ast with_type =
 		raise (Parser.TypePath ([n],None,false))
 	| Error (Type_not_found (path,_),_) as err ->
 		begin try
-			raise (Display.DisplayFields (get_submodule_fields ctx path))
+			raise (Display.DisplayFields (DisplayFields.get_submodule_fields ctx path))
 		with Not_found ->
 			raise err
 		end
@@ -3885,169 +3784,7 @@ and display_expr ctx e_ast e with_type p =
 	| DMToplevel ->
 		raise (Display.DisplayToplevel (DisplayToplevel.collect ctx false))
 	| DMField | DMNone | DMModuleSymbols _ | DMDiagnostics _ | DMStatistics ->
-		let opt_args args ret = TFun(List.map(fun (n,o,t) -> n,true,t) args,ret) in
-		let e = match e.eexpr with
-			| TField (e1,fa) ->
-				if field_name fa = "bind" then (match follow e1.etype with
-					| TFun(args,ret) -> {e1 with etype = opt_args args ret}
-					| _ -> e)
-				else
-					e
-			| _ ->
-				e
-		in
-		let opt_type t =
-			match t with
-			| TLazy f ->
-				Typeload.return_partial_type := true;
-				let t = lazy_type f in
-				Typeload.return_partial_type := false;
-				t
-			| _ ->
-				t
-		in
-		let should_access c cf stat =
-			if c != ctx.curclass && not cf.cf_public && String.length cf.cf_name > 4 then begin match String.sub cf.cf_name 0 4 with
-				| "get_" | "set_" -> false
-				| _ -> can_access ctx c cf stat
-			end else
-				can_access ctx c cf stat
-		in
-		let rec get_fields t =
-			match follow t with
-			| TInst (c,params) ->
-				if Meta.has Meta.CoreApi c.cl_meta then merge_core_doc ctx c;
-				let merge ?(cond=(fun _ -> true)) a b =
-					PMap.foldi (fun k f m -> if cond f then PMap.add k f m else m) a b
-				in
-				let rec loop c params =
-					let m = List.fold_left (fun m (i,params) ->
-						merge m (loop i params)
-					) PMap.empty c.cl_implements in
-					let m = (match c.cl_super with
-						| None -> m
-						| Some (csup,cparams) -> merge m (loop csup cparams)
-					) in
-					let m = merge ~cond:(fun f -> should_access c f false) c.cl_fields m in
-					let m = (match c.cl_kind with
-						| KTypeParameter pl -> List.fold_left (fun acc t -> merge acc (get_fields t)) m pl
-						| _ -> m
-					) in
-					PMap.map (fun f -> { f with cf_type = apply_params c.cl_params params (opt_type f.cf_type); cf_public = true; }) m
-				in
-				loop c params
-			| TAbstract({a_impl = Some c} as a,pl) ->
-				if Meta.has Meta.CoreApi c.cl_meta then merge_core_doc ctx c;
-				let fields = try
-					let _,el,_ = Meta.get Meta.Forward a.a_meta in
-					let sl = ExtList.List.filter_map (fun e -> match fst e with
-						| EConst(Ident s) -> Some s
-						| _ -> None
-					) el in
-					let fields = get_fields (apply_params a.a_params pl a.a_this) in
-					if sl = [] then fields else PMap.fold (fun cf acc ->
-						if List.mem cf.cf_name sl then
-							PMap.add cf.cf_name cf acc
-						else
-							acc
-					) fields PMap.empty
-				with Not_found ->
-					PMap.empty
-				in
-				PMap.fold (fun f acc ->
-					if f.cf_name <> "_new" && should_access c f true && Meta.has Meta.Impl f.cf_meta && not (Meta.has Meta.Enum f.cf_meta) then begin
-						let f = prepare_using_field f in
-						let t = apply_params a.a_params pl (follow f.cf_type) in
-						PMap.add f.cf_name { f with cf_public = true; cf_type = opt_type t } acc
-					end else
-						acc
-				) c.cl_statics fields
-			| TAnon a when PMap.is_empty a.a_fields ->
-				begin match with_type with
-				| WithType t -> get_fields t
-				| _ -> a.a_fields
-				end
-			| TAnon a ->
-				(match !(a.a_status) with
-				| Statics c ->
-					if Meta.has Meta.CoreApi c.cl_meta then merge_core_doc ctx c;
-					let is_abstract_impl = match c.cl_kind with KAbstractImpl _ -> true | _ -> false in
-					let pm = match c.cl_constructor with None -> PMap.empty | Some cf -> PMap.add "new" cf PMap.empty in
-					PMap.fold (fun f acc ->
-						if should_access c f true && (not is_abstract_impl || not (Meta.has Meta.Impl f.cf_meta) || Meta.has Meta.Enum f.cf_meta) then
-							PMap.add f.cf_name { f with cf_public = true; cf_type = opt_type f.cf_type } acc else acc
-					) a.a_fields pm
-				| _ ->
-					a.a_fields)
-			| TFun (args,ret) ->
-				let t = opt_args args ret in
-				let cf = mk_field "bind" (tfun [t] t) p null_pos in
-				cf.cf_kind <- Method MethNormal;
-				PMap.add "bind" cf PMap.empty
-			| _ ->
-				PMap.empty
-		in
-		let fields = get_fields e.etype in
-		(*
-			add 'using' methods compatible with this type
-		*)
-		let rec loop acc = function
-			| [] -> acc
-			| (c,_) :: l ->
-				let acc = ref (loop acc l) in
-				let rec dup t = Type.map dup t in
-				List.iter (fun f ->
-					if not (Meta.has Meta.NoUsing f.cf_meta) && not (Meta.has Meta.Impl f.cf_meta) then
-					let f = { f with cf_type = opt_type f.cf_type } in
-					let monos = List.map (fun _ -> mk_mono()) f.cf_params in
-					let map = apply_params f.cf_params monos in
-					match follow (map f.cf_type) with
-					| TFun((_,_,TType({t_path=["haxe";"macro"], "ExprOf"}, [t])) :: args, ret)
-					| TFun((_,_,t) :: args, ret) ->
-						(try
-							unify_raise ctx (dup e.etype) t e.epos;
-							List.iter2 (fun m (name,t) -> match follow t with
-								| TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
-									List.iter (fun tc -> unify_raise ctx m (map tc) e.epos) constr
-								| _ -> ()
-							) monos f.cf_params;
-							if not (can_access ctx c f true) || follow e.etype == t_dynamic && follow t != t_dynamic then
-								()
-							else begin
-								let f = prepare_using_field f in
-								let f = { f with cf_params = []; cf_public = true; cf_type = TFun(args,ret) } in
-								acc := PMap.add f.cf_name f (!acc)
-							end
-						with Error (Unify _,_) -> ())
-					| _ -> ()
-				) c.cl_ordered_statics;
-				!acc
-		in
-		let use_methods = match follow e.etype with TMono _ -> PMap.empty | _ -> loop (loop PMap.empty ctx.g.global_using) ctx.m.module_using in
-		let fields = PMap.fold (fun f acc -> PMap.add f.cf_name f acc) fields use_methods in
-		let fields = match fst e_ast with
-			| EConst(String s) when String.length s = 1 ->
-				let cf = mk_field "code" ctx.t.tint e.epos null_pos in
-				cf.cf_doc <- Some "The character code of this character (inlined at compile-time).";
-				cf.cf_kind <- Var { v_read = AccNormal; v_write = AccNever };
-				PMap.add cf.cf_name cf fields
-			| _ ->
-				fields
-		in
-		let fields = PMap.fold (fun f acc -> if Meta.has Meta.NoCompletion f.cf_meta then acc else f :: acc) fields [] in
-		let get_field acc f =
-			List.fold_left (fun acc f ->
-				let kind = match f.cf_kind with Method _ -> Display.FKMethod f.cf_type | Var _ -> Display.FKVar f.cf_type in
-				if f.cf_public then (f.cf_name,kind,f.cf_doc) :: acc else acc
-			) acc (f :: f.cf_overloads)
-		in
-		let fields = List.fold_left get_field [] fields in
-		let fields = try
-			let sl = string_list_of_expr_path_raise e_ast in
-			fields @ get_submodule_fields ctx (List.tl sl,List.hd sl)
-		with Exit | Not_found ->
-			fields
-		in
+		let fields = DisplayFields.collect ctx e_ast e with_type p in
 		raise (Display.DisplayFields fields)
 
 and maybe_type_against_enum ctx f with_type iscall p =