Skip to content

Commit

Permalink
Rework module resolution (#11168)
Browse files Browse the repository at this point in the history
* start on m.module_resolution

* support static inits

* finish module_globals removal

* remove wildcard_packages

* get cursed resolution tests to pass

* add some debug and a test of the current behavior (see #9197)

* remove early import resolving and fix python test

* turn into class

* add RLazy

* (finally) remove context_init

* don't expand for type lookups

* fix 2/3 of broken display test

* rename some things

* make immutable

* add own_resolution

* avoid some duplicate lookuppery

* distinguish class and abstract statics

* move enum expansion to resolution_list

* move to own module

* add test for alias conflict

* add test

#closes 2729

* add actual resolve method and try some caching

* change expected enum typing

* try something different

* merge aliases into resolution_kind

* remove add_l

* add some timers and a type import cache

* deal with weirdness

* remove weird import lookup

see #9150

* meh

* asdfg

* keep weird handling for now to have CI green

* investigate

* add timer for flush_pass

* add absurd amount of timers

* Revert "add absurd amount of timers"

This reverts commit 1c49717.

* Revert "add timer for flush_pass"

This reverts commit 935946b.

* Revert "investigate"

This reverts commit de52786.

* fix test

* Remove unused open

* remove timers

for now

---------

Co-authored-by: Rudy Ges <[email protected]>
  • Loading branch information
Simn and kLabz authored Oct 20, 2023
1 parent c2479a0 commit d0016c9
Show file tree
Hide file tree
Showing 35 changed files with 729 additions and 383 deletions.
18 changes: 8 additions & 10 deletions src/compiler/retyper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ let pair_class_field rctx ctx cctx fctx cf cff p =
remove_class_field_flag cf CfPostProcessed;
)

let pair_classes rctx context_init c d p =
let pair_classes rctx c d p =
let rctx = {rctx with
print_stack = (Printf.sprintf "[Class %s]" (s_type_path c.cl_path)) :: rctx.print_stack
} in
c.cl_restore();
(* TODO: What do we do with build macros? *)
let cctx = create_class_context c context_init p in
let cctx = create_class_context c p in
let ctx = create_typer_context_for_class rctx.typer cctx p in
let _ =
let rctx = {rctx with
Expand Down Expand Up @@ -180,14 +180,14 @@ let pair_typedefs ctx rctx td d =
ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false d.d_data));
[]

let pair_abstracts ctx rctx context_init a d p =
let pair_abstracts ctx rctx a d p =
let rctx = {rctx with
print_stack = (Printf.sprintf "[Abstract %s]" (s_type_path a.a_path)) :: rctx.print_stack
} in
match a.a_impl with
| Some c ->
c.cl_restore();
let cctx = create_class_context c context_init p in
let cctx = create_class_context c p in
let ctx = create_typer_context_for_class rctx.typer cctx p in
let fl = List.map (fun cff ->
let cff = TypeloadFields.transform_abstract_field2 ctx a cff in
Expand Down Expand Up @@ -218,7 +218,6 @@ let attempt_retyping ctx m p =
print_stack = [Printf.sprintf "[Module %s]" (s_type_path m.m_path)];
} in
(* log rctx 0 (Printf.sprintf "Retyping module %s" (s_type_path m.m_path)); *)
let context_init = new TypeloadFields.context_init in
let find_type name = try
List.find (fun t -> snd (t_infos t).mt_path = name) ctx.m.curmod.m_types
with Not_found ->
Expand All @@ -230,11 +229,11 @@ let attempt_retyping ctx m p =
| (d,p) :: decls ->
begin match d with
| EImport (path,mode) ->
ImportHandling.init_import ctx context_init path mode p;
ImportHandling.init_import ctx path mode p;
ImportHandling.commit_import ctx path mode p;
loop acc decls
| EUsing path ->
ImportHandling.init_using ctx context_init path p;
ImportHandling.init_using ctx path p;
loop acc decls
| EClass c ->
let mt = find_type (fst c.d_name) in
Expand All @@ -257,18 +256,17 @@ let attempt_retyping ctx m p =
let pairs = loop [] decls in
let fl = List.map (fun (d,mt) -> match d,mt with
| EClass d,TClassDecl c ->
pair_classes rctx context_init c d p
pair_classes rctx c d p
| EEnum d,TEnumDecl en ->
pair_enums ctx rctx en d
| ETypedef d,TTypeDecl td ->
pair_typedefs ctx rctx td d
| EAbstract d,TAbstractDecl a ->
pair_abstracts ctx rctx context_init a d p
pair_abstracts ctx rctx a d p
| _ ->
fail rctx "?"
) pairs in
(* If we get here we know that the everything is ok. *)
delay ctx PConnectField (fun () -> context_init#run);
List.iter (fun fl ->
List.iter (fun f -> f()) fl
) fl;
Expand Down
11 changes: 11 additions & 0 deletions src/context/display/displayEmitter.ml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ let symbol_of_module_type = function
| TTypeDecl td -> SKTypedef td
| TAbstractDecl a -> SKAbstract a

let display_alias ctx name t p = match ctx.com.display.dms_kind with
| DMDefinition | DMTypeDefinition ->
raise_positions [p];
| DMUsage _ | DMImplementation ->
ReferencePosition.set (name,p,SKOther)
| DMHover ->
let ct = CompletionType.from_type (get_import_status ctx) t in
raise_hover (make_ci_literal name (t,ct)) None p
| _ ->
()

let display_module_type ctx mt p = match ctx.com.display.dms_kind with
| DMDefinition | DMTypeDefinition ->
begin match mt with
Expand Down
3 changes: 1 addition & 2 deletions src/context/display/displayTexpr.ml
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ let find_abstract_by_position decls p =
loop decls

let actually_check_display_field ctx c cff p =
let context_init = new TypeloadFields.context_init in
let cctx = TypeloadFields.create_class_context c context_init p in
let cctx = TypeloadFields.create_class_context c p in
let ctx = TypeloadFields.create_typer_context_for_class ctx cctx p in
let cff = TypeloadFields.transform_field (ctx,cctx) c cff (ref []) (pos cff.cff_name) in
let display_modifier = Typeload.check_field_access ctx cff in
Expand Down
8 changes: 4 additions & 4 deletions src/context/display/displayToplevel.ml
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ module CollectionContext = struct
Shadowed
with Not_found ->
let check_wildcard () =
List.exists (fun (sl,_) -> (sl,snd path) = path) ctx.ctx.m.wildcard_packages
List.exists (fun (sl,_) -> (sl,snd path) = path) ctx.ctx.m.import_resolution#extract_wildcard_packages
in
if is_import || (fst path = []) || check_wildcard () then Imported else Unimported

Expand Down Expand Up @@ -377,7 +377,7 @@ let collect ctx tk with_type sort =
()
in
List.iter enum_ctors ctx.m.curmod.m_types;
List.iter enum_ctors (List.map fst ctx.m.module_imports);
List.iter enum_ctors (List.map fst ctx.m.import_resolution#extract_type_imports);

(* enum constructors of expected type *)
begin match with_type with
Expand Down Expand Up @@ -414,7 +414,7 @@ let collect ctx tk with_type sort =
| _ -> raise Not_found
with Not_found ->
()
) ctx.m.module_globals;
) ctx.m.import_resolution#extract_field_imports;

(* literals *)
add (make_ci_literal "null" (tpair t_dynamic)) (Some "null");
Expand Down Expand Up @@ -459,7 +459,7 @@ let collect ctx tk with_type sort =
List.iter add_type ctx.m.curmod.m_types;

(* module imports *)
List.iter add_type (List.rev_map fst ctx.m.module_imports); (* reverse! *)
List.iter add_type (List.rev_map fst ctx.m.import_resolution#extract_type_imports); (* reverse! *)

(* types from files *)
let cs = ctx.com.cs in
Expand Down
110 changes: 58 additions & 52 deletions src/context/display/importHandling.ml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ open Common
open Type
open Error
open Typecore
open Resolution

type import_display_kind =
| IDKPackage of string list
Expand Down Expand Up @@ -61,7 +62,7 @@ let commit_import ctx path mode p =
ctx.m.import_statements <- (path,mode) :: ctx.m.import_statements;
if Filename.basename p.pfile <> "import.hx" then add_import_position ctx p path

let init_import ctx context_init path mode p =
let init_import ctx path mode p =
let rec loop acc = function
| x :: l when is_lower_ident (fst x) -> loop (x::acc) l
| rest -> List.rev acc, rest
Expand All @@ -71,7 +72,7 @@ let init_import ctx context_init path mode p =
| [] ->
(match mode with
| IAll ->
ctx.m.wildcard_packages <- (List.map fst pack,p) :: ctx.m.wildcard_packages
ctx.m.import_resolution#add (wildcard_package_resolution (List.map fst pack) p)
| _ ->
(match List.rev path with
(* p spans `import |` (to the display position), so we take the pmax here *)
Expand All @@ -82,7 +83,7 @@ let init_import ctx context_init path mode p =
let p_type = punion p1 p2 in
let md = ctx.g.do_load_module ctx (List.map fst pack,tname) p_type in
let types = md.m_types in
let no_private (t,_) = not (t_infos t).mt_private in
let not_private mt = not (t_infos mt).mt_private in
let error_private p = raise_typing_error "Importing private declarations from a module is not allowed" p in
let chk_private t p = if ctx.m.curmod != (t_infos t).mt_module && (t_infos t).mt_private then error_private p in
let has_name name t = snd (t_infos t).mt_path = name in
Expand All @@ -109,66 +110,70 @@ let init_import ctx context_init path mode p =
chk_private t p_type;
t
in
let rebind t name p =
let check_alias mt name pname =
if not (name.[0] >= 'A' && name.[0] <= 'Z') then
raise_typing_error "Type aliases must start with an uppercase letter" p;
let _, _, f = ctx.g.do_build_instance ctx t p_type in
(* create a temp private typedef, does not register it in module *)
let t_path = (fst md.m_path @ ["_" ^ snd md.m_path],name) in
let t_type = f (extract_param_types (t_infos t).mt_params) in
let mt = TTypeDecl {(mk_typedef ctx.m.curmod t_path p p t_type) with
t_private = true;
t_params = (t_infos t).mt_params
} in
if ctx.is_display_file && DisplayPosition.display_position#enclosed_in p then
DisplayEmitter.display_module_type ctx mt p;
mt
raise_typing_error "Type aliases must start with an uppercase letter" pname;
if ctx.is_display_file && DisplayPosition.display_position#enclosed_in pname then
DisplayEmitter.display_alias ctx name (type_of_module_type mt) pname;
in
let add_static_init t name s =
let name = (match name with None -> s | Some (n,_) -> n) in
match resolve_typedef t with
| TClassDecl c | TAbstractDecl {a_impl = Some c} ->
| TClassDecl c ->
ignore(c.cl_build());
ignore(PMap.find s c.cl_statics);
ctx.m.module_globals <- PMap.add name (TClassDecl c,s,p) ctx.m.module_globals
| TEnumDecl e ->
ignore(PMap.find s e.e_constrs);
ctx.m.module_globals <- PMap.add name (TEnumDecl e,s,p) ctx.m.module_globals
let cf = PMap.find s c.cl_statics in
static_field_resolution c cf name p
| TAbstractDecl ({a_impl = Some c} as a) ->
ignore(c.cl_build());
let cf = PMap.find s c.cl_statics in
static_abstract_field_resolution a c cf name p
| TEnumDecl en ->
let ef = PMap.find s en.e_constrs in
enum_constructor_resolution en ef name p
| _ ->
raise Not_found
in
let add_lazy_resolution f =
ctx.m.import_resolution#add (lazy_resolution f)
in
(match mode with
| INormal | IAsName _ ->
let name = (match mode with IAsName n -> Some n | _ -> None) in
(match rest with
| [] ->
(match name with
begin match name with
| None ->
ctx.m.module_imports <- List.filter no_private (List.map (fun t -> t,p) types) @ ctx.m.module_imports;
List.iter (fun mt ->
if not_private mt then
ctx.m.import_resolution#add (module_type_resolution mt None p)
) (List.rev types);
Option.may (fun c ->
context_init#add (fun () ->
ignore(c.cl_build());
List.iter (fun cf ->
if has_class_field_flag cf CfPublic then
ctx.m.module_globals <- PMap.add cf.cf_name (TClassDecl c,cf.cf_name,p) ctx.m.module_globals
) c.cl_ordered_statics
);
ctx.m.import_resolution#add (class_statics_resolution c p)
) md.m_statics
| Some(newname,pname) ->
ctx.m.module_imports <- (rebind (get_type tname) newname pname,p) :: ctx.m.module_imports);
let mt = get_type tname in
check_alias mt newname pname;
ctx.m.import_resolution#add (module_type_resolution mt (Some newname) p2)
end
| [tsub,p2] ->
let pu = punion p1 p2 in
(try
let tsub = List.find (has_name tsub) types in
chk_private tsub pu;
ctx.m.module_imports <- ((match name with None -> tsub | Some(n,pname) -> rebind tsub n pname),p) :: ctx.m.module_imports
let alias = match name with
| None ->
None
| Some(name,pname) ->
check_alias tsub name pname;
Some name
in
ctx.m.import_resolution#add (module_type_resolution tsub alias p2);
with Not_found ->
(* this might be a static property, wait later to check *)
let find_main_type_static () =
try
let tmain = find_type tname in
begin try
add_static_init tmain name tsub
Some (add_static_init tmain (Option.map fst name) tsub)
with Not_found ->
let parent,target_kind,candidates = match resolve_typedef tmain with
| TClassDecl c ->
Expand All @@ -189,13 +194,13 @@ let init_import ctx context_init path mode p =
(* TODO: cleaner way to get module fields? *)
PMap.foldi (fun n _ acc -> n :: acc) (try (Option.get md.m_statics).cl_statics with | _ -> PMap.empty) []
in

display_error ctx.com (StringError.string_error tsub candidates (parent ^ " has no " ^ target_kind ^ " " ^ tsub)) p
display_error ctx.com (StringError.string_error tsub candidates (parent ^ " has no " ^ target_kind ^ " " ^ tsub)) p;
None
end
with Not_found ->
fail_usefully tsub p
in
context_init#add (fun() ->
add_lazy_resolution (fun() ->
match md.m_statics with
| Some c ->
(try
Expand All @@ -208,8 +213,7 @@ let init_import ctx context_init path mode p =
if not (has_class_field_flag cf CfPublic) then
error_private p
else
let imported_name = match name with None -> tsub | Some (n,pname) -> n in
ctx.m.module_globals <- PMap.add imported_name (TClassDecl c,tsub,p) ctx.m.module_globals;
Some (static_field_resolution c cf (Option.map fst name) p)
else
loop rest
in
Expand All @@ -225,11 +229,12 @@ let init_import ctx context_init path mode p =
| [] -> ()
| (n,p) :: _ -> raise_typing_error ("Unexpected " ^ n) p);
let tsub = get_type tsub in
context_init#add (fun() ->
add_lazy_resolution (fun() ->
try
add_static_init tsub name fname
Some (add_static_init tsub (Option.map fst name) fname)
with Not_found ->
display_error ctx.com (s_type_path (t_infos tsub).mt_path ^ " has no field " ^ fname) (punion p p3)
display_error ctx.com (s_type_path (t_infos tsub).mt_path ^ " has no field " ^ fname) (punion p p3);
None
);
)
| IAll ->
Expand All @@ -238,14 +243,13 @@ let init_import ctx context_init path mode p =
| [tsub,_] -> get_type tsub
| _ :: (n,p) :: _ -> raise_typing_error ("Unexpected " ^ n) p
) in
context_init#add (fun() ->
add_lazy_resolution (fun() ->
match resolve_typedef t with
| TClassDecl c
| TAbstractDecl {a_impl = Some c} ->
ignore(c.cl_build());
PMap.iter (fun _ cf -> if not (has_meta Meta.NoImportGlobal cf.cf_meta) then ctx.m.module_globals <- PMap.add cf.cf_name (TClassDecl c,cf.cf_name,p) ctx.m.module_globals) c.cl_statics
| TEnumDecl e ->
PMap.iter (fun _ c -> if not (has_meta Meta.NoImportGlobal c.ef_meta) then ctx.m.module_globals <- PMap.add c.ef_name (TEnumDecl e,c.ef_name,p) ctx.m.module_globals) e.e_constrs
Some (class_statics_resolution c p)
| TEnumDecl en ->
Some (enum_statics_resolution en p)
| _ ->
raise_typing_error "No statics to import from this type" p
)
Expand All @@ -270,7 +274,6 @@ let handle_using ctx path p =
let t = ctx.g.do_load_type_def ctx p t in
[t]
) in
(* delay the using since we need to resolve typedefs *)
let filter_classes types =
let rec loop acc types = match types with
| td :: l ->
Expand All @@ -286,8 +289,11 @@ let handle_using ctx path p =
in
types,filter_classes

let init_using ctx context_init path p =
let init_using ctx path p =
let types,filter_classes = handle_using ctx path p in
(* do the import first *)
ctx.m.module_imports <- (List.map (fun t -> t,p) types) @ ctx.m.module_imports;
context_init#add (fun() -> ctx.m.module_using <- filter_classes types @ ctx.m.module_using)
List.iter (fun mt ->
ctx.m.import_resolution#add (module_type_resolution mt None p)
) (List.rev types);
(* delay the using since we need to resolve typedefs *)
delay_late ctx PConnectField (fun () -> ctx.m.module_using <- filter_classes types @ ctx.m.module_using)
Loading

0 comments on commit d0016c9

Please sign in to comment.