Browse Source

Change Path.unique_file_path to an explicit key type (#9283)

* change Path.unique_file_path to an explicit key type

* update to latest changes

* update tests
Aleksandr Kuzmenko 5 years ago
parent
commit
acaec1c8a0
41 changed files with 144 additions and 106 deletions
  1. 2 2
      src/codegen/gencommon/gencommon.ml
  2. 6 5
      src/compiler/displayOutput.ml
  3. 11 10
      src/compiler/server.ml
  4. 10 8
      src/context/compilationServer.ml
  5. 5 5
      src/context/display/diagnostics.ml
  6. 2 2
      src/context/display/diagnosticsPrinter.ml
  7. 1 1
      src/context/display/diagnosticsTypes.ml
  8. 1 1
      src/context/display/display.ml
  9. 9 8
      src/context/display/displayJson.ml
  10. 4 4
      src/context/display/displayTexpr.ml
  11. 9 9
      src/context/display/displayToplevel.ml
  12. 1 1
      src/context/display/findReferences.ml
  13. 4 4
      src/context/display/statistics.ml
  14. 2 2
      src/context/display/syntaxExplorer.ml
  15. 4 3
      src/context/typecore.ml
  16. 18 3
      src/core/display/displayPosition.ml
  17. 1 1
      src/core/displayTypes.ml
  18. 28 7
      src/core/path.ml
  19. 1 1
      src/generators/gencs.ml
  20. 1 1
      src/generators/genjava.ml
  21. 1 1
      src/macro/eval/evalContext.ml
  22. 2 2
      src/macro/eval/evalDebugMisc.ml
  23. 1 1
      src/macro/eval/evalDebugSocket.ml
  24. 2 2
      src/macro/macroApi.ml
  25. 1 1
      src/optimization/dce.ml
  26. 1 1
      src/syntax/grammar.mly
  27. 1 1
      src/syntax/parser.ml
  28. 1 1
      src/syntax/parserEntry.ml
  29. 1 1
      src/typing/typeloadModule.ml
  30. 2 2
      src/typing/typeloadParse.ml
  31. 1 1
      tests/misc/projects/Issue1968/compile.hxml.stderr
  32. 1 1
      tests/misc/projects/Issue2991/compile.hxml.stderr
  33. 1 1
      tests/misc/projects/Issue2993/compile.hxml.stderr
  34. 1 1
      tests/misc/projects/Issue2995/position.hxml.stderr
  35. 2 2
      tests/misc/projects/Issue2995/usage.hxml.stderr
  36. 1 1
      tests/misc/projects/Issue2996/compile1.hxml.stderr
  37. 1 1
      tests/misc/projects/Issue2996/compile2.hxml.stderr
  38. 1 1
      tests/misc/projects/Issue2997/compile1.hxml.stderr
  39. 1 1
      tests/misc/projects/Issue5123/compile.hxml.stderr
  40. 1 3
      tests/misc/src/Main.hx
  41. 0 2
      tests/sys/src/TestFileSystem.hx

+ 2 - 2
src/codegen/gencommon/gencommon.ml

@@ -839,7 +839,7 @@ let write_file gen w source_dir path extension out_files =
 		close_out f
 	end;
 
-	out_files := (Path.unique_full_path s_path) :: !out_files;
+	out_files := (Path.UniqueKey.create s_path) :: !out_files;
 
 	t()
 
@@ -854,7 +854,7 @@ let clean_files path excludes verbose =
 				let pack = pack @ [file] in
 				iter_files (pack) (Unix.opendir filepath) filepath;
 				try Unix.rmdir filepath with Unix.Unix_error (ENOTEMPTY,_,_) -> ();
-			else if not (String.ends_with filepath ".meta") && not (List.mem (Path.unique_full_path filepath) excludes) then begin
+			else if not (String.ends_with filepath ".meta") && not (List.mem (Path.UniqueKey.create filepath) excludes) then begin
 				if verbose then print_endline ("Removing " ^ filepath);
 			 	Sys.remove filepath
 			end

+ 6 - 5
src/compiler/displayOutput.ml

@@ -141,7 +141,7 @@ let print_type t p doc =
 	if p = null_pos then
 		Buffer.add_string b "<type"
 	else begin
-		let error_printer file line = Printf.sprintf "%s:%d:" (Path.unique_full_path file) line in
+		let error_printer file line = Printf.sprintf "%s:%d:" (Path.get_full_path file) line in
 		let epos = Lexer.get_error_pos error_printer p in
 		Buffer.add_string b ("<type p=\"" ^ (htmlescape epos) ^ "\"")
 	end;
@@ -235,7 +235,7 @@ let handle_display_argument com file_pos pre_compilation did_something =
 	| _ ->
 		let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format: " ^ file_pos) in
 		let file = unquote file in
-		let file_unique = Path.unique_full_path file in
+		let file_unique = Path.UniqueKey.create file in
 		let pos, smode = try ExtString.String.split pos "@" with _ -> pos,"" in
 		let mode = match smode with
 			| "position" ->
@@ -284,12 +284,12 @@ let handle_display_argument com file_pos pre_compilation did_something =
 		Parser.display_mode := mode;
 		if not com.display.dms_full_typing then Common.define_value com Define.Display (if smode <> "" then smode else "1");
 		DisplayPosition.display_position#set {
-			pfile = file_unique;
+			pfile = Path.get_full_path file;
 			pmin = pos;
 			pmax = pos;
 		}
 
-let file_input_marker = Path.unique_full_path "? input"
+let file_input_marker = Path.get_full_path "? input"
 
 type display_path_kind =
 	| DPKNormal of path
@@ -428,7 +428,8 @@ let process_global_display_mode com tctx =
 			| None -> []
 			| Some cs ->
 				let l = cs#get_context_files ((Define.get_signature com.defines) :: (match com.get_macros() with None -> [] | Some com -> [Define.get_signature com.defines])) in
-				List.fold_left (fun acc (file,cfile) ->
+				List.fold_left (fun acc (file_key,cfile) ->
+					let file = cfile.CompilationServer.c_file_path in
 					if (filter <> None || DisplayPosition.display_position#is_in_file file) then
 						(file,DocumentSymbols.collect_module_symbols (filter = None) (cfile.c_package,cfile.c_decls)) :: acc
 					else

+ 11 - 10
src/compiler/server.ml

@@ -122,8 +122,9 @@ let current_stdin = ref None
 
 let parse_file cs com file p =
 	let cc = CommonCache.get_cache cs com in
-	let ffile = Path.unique_full_path file in
-	let is_display_file = ffile = (DisplayPosition.display_position#get).pfile in
+	let ffile = Path.get_full_path file
+	and fkey = Path.UniqueKey.create file in
+	let is_display_file = DisplayPosition.display_position#is_in_file ffile in
 	match is_display_file, !current_stdin with
 	| true, Some stdin when Common.defined com Define.DisplayStdin ->
 		TypeloadParse.parse_file_from_string com file p stdin
@@ -131,7 +132,7 @@ let parse_file cs com file p =
 		let ftime = file_time ffile in
 		let data = Std.finally (Timer.timer ["server";"parser cache"]) (fun () ->
 			try
-				let cfile = cc#find_file ffile in
+				let cfile = cc#find_file fkey in
 				if cfile.c_time <> ftime then raise Not_found;
 				Parser.ParseSuccess((cfile.c_package,cfile.c_decls),false,cfile.c_pdi)
 			with Not_found ->
@@ -143,7 +144,7 @@ let parse_file cs com file p =
 							if pdi.pd_errors <> [] then
 								"not cached, is display file with parse errors",true
 							else if com.display.dms_per_file then begin
-								cc#cache_file ffile ftime data pdi;
+								cc#cache_file fkey ffile ftime data pdi;
 								"cached, is intact display file",true
 							end else
 								"not cached, is display file",true
@@ -151,10 +152,10 @@ let parse_file cs com file p =
 							(* We assume that when not in display mode it's okay to cache stuff that has #if display
 							checks. The reasoning is that non-display mode has more information than display mode. *)
 							if not com.display.dms_display then raise Not_found;
-							let ident = Hashtbl.find Parser.special_identifier_files ffile in
+							let ident = Hashtbl.find Parser.special_identifier_files fkey in
 							Printf.sprintf "not cached, using \"%s\" define" ident,true
 						with Not_found ->
-							cc#cache_file ffile ftime data pdi;
+							cc#cache_file fkey ffile ftime data pdi;
 							"cached",false
 						end
 				in
@@ -286,9 +287,9 @@ let check_module sctx ctx m p =
 	let com = ctx.Typecore.com in
 	let cc = CommonCache.get_cache sctx.cs com in
 	let content_changed m file =
-		let ffile = Path.unique_full_path file in
+		let fkey = Path.UniqueKey.create file in
 		try
-			let cfile = cc#find_file ffile in
+			let cfile = cc#find_file fkey in
 			(* We must use the module path here because the file path is absolute and would cause
 				positions in the parsed declarations to differ. *)
 			let new_data = TypeloadParse.parse_module ctx m.m_path p in
@@ -330,7 +331,7 @@ let check_module sctx ctx m p =
 						match load m.m_path p with
 						| None -> loop l
 						| Some _ ->
-							if Path.unique_full_path file <> m.m_extra.m_file then begin
+							if Path.UniqueKey.create file <> Path.UniqueKey.create m.m_extra.m_file then begin
 								if sctx.verbose then print_endline ("Library file was changed for " ^ s_type_path m.m_path); (* TODO *)
 								raise Not_found;
 							end
@@ -362,7 +363,7 @@ let check_module sctx ctx m p =
 					ServerMessage.unchanged_content com "" m.m_extra.m_file;
 				end else begin
 					ServerMessage.not_cached com "" m;
-					if m.m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules m.m_extra.m_file;
+					if m.m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules (Path.UniqueKey.create m.m_extra.m_file);
 					raise Not_found;
 				end
 			end

+ 10 - 8
src/context/compilationServer.ml

@@ -5,6 +5,7 @@ open Type
 open Define
 
 type cached_file = {
+	c_file_path : string;
 	c_time : float;
 	c_package : string list;
 	c_decls : type_decl list;
@@ -23,7 +24,7 @@ type cached_native_lib = {
 }
 
 class context_cache (index : int) = object(self)
-	val files : (string,cached_file) Hashtbl.t = Hashtbl.create 0
+	val files : (Path.UniqueKey.t,cached_file) Hashtbl.t = Hashtbl.create 0
 	val modules : (path,module_def) Hashtbl.t = Hashtbl.create 0
 	val removed_files = Hashtbl.create 0
 	val mutable json = JNull
@@ -34,14 +35,15 @@ class context_cache (index : int) = object(self)
 	method find_file key =
 		Hashtbl.find files key
 
-	method cache_file key time data pdi =
-		Hashtbl.replace files key { c_time = time; c_package = fst data; c_decls = snd data; c_module_name = None; c_pdi = pdi }
+	method cache_file key path time data pdi =
+		Hashtbl.replace files key { c_file_path = path; c_time = time; c_package = fst data; c_decls = snd data; c_module_name = None; c_pdi = pdi }
 
 	method remove_file key =
-		if Hashtbl.mem files key then begin
+		try
+			let f = Hashtbl.find files key in
 			Hashtbl.remove files key;
-			Hashtbl.replace removed_files key ()
-		end
+			Hashtbl.replace removed_files key f.c_file_path
+		with Not_found -> ()
 
 	(* Like remove_file, but doesn't keep track of the file *)
 	method remove_file_for_real key =
@@ -158,10 +160,10 @@ class cache = object(self)
 			) cc#get_modules acc
 		) contexts []
 
-	method taint_modules file =
+	method taint_modules file_key =
 		Hashtbl.iter (fun _ cc ->
 			Hashtbl.iter (fun _ m ->
-				if m.m_extra.m_file = file then m.m_extra.m_dirty <- Some m.m_path
+				if Path.UniqueKey.create m.m_extra.m_file = file_key then m.m_extra.m_dirty <- Some m.m_path
 			) cc#get_modules
 		) contexts
 

+ 5 - 5
src/context/display/diagnostics.ml

@@ -121,17 +121,17 @@ let prepare com =
 			let is_true defines e =
 				ParserEntry.is_true (ParserEntry.eval defines e)
 			in
-			Hashtbl.iter (fun file cfile ->
-				if DisplayPosition.display_position#is_in_file file then begin
+			Hashtbl.iter (fun file_key cfile ->
+				if DisplayPosition.display_position#is_in_file cfile.CompilationServer.c_file_path then begin
 					let dead_blocks = cfile.CompilationServer.c_pdi.pd_dead_blocks in
 					let dead_blocks = List.filter (fun (_,e) -> not (is_true display_defines e)) dead_blocks in
 					try
-						let dead_blocks2 = Hashtbl.find dctx.dead_blocks file in
+						let dead_blocks2 = Hashtbl.find dctx.dead_blocks file_key in
 						(* Intersect *)
 						let dead_blocks2 = List.filter (fun (p,_) -> List.mem_assoc p dead_blocks) dead_blocks2 in
-						Hashtbl.replace dctx.dead_blocks file dead_blocks2
+						Hashtbl.replace dctx.dead_blocks file_key dead_blocks2
 					with Not_found ->
-						Hashtbl.add dctx.dead_blocks file dead_blocks
+						Hashtbl.add dctx.dead_blocks file_key dead_blocks
 				end
 			) cc#get_files
 		| None ->

+ 2 - 2
src/context/display/diagnosticsPrinter.ml

@@ -8,10 +8,10 @@ open DiagnosticsTypes
 type t = DiagnosticsKind.t * pos
 
 let is_diagnostics_file file =
-	let file = Path.unique_full_path file in
+	let key = Path.UniqueKey.create file in
 	match (!Parser.display_mode) with
 	| DMDiagnostics [] -> true
-	| DMDiagnostics files -> List.exists (fun file' -> file = file') files
+	| DMDiagnostics file_keys -> List.exists (fun key' -> key = key') file_keys
 	| _ -> false
 
 module UnresolvedIdentifierSuggestion = struct

+ 1 - 1
src/context/display/diagnosticsTypes.ml

@@ -4,7 +4,7 @@ open Ast
 type diagnostics_context = {
 	mutable removable_code : (string * pos * pos) list;
 	mutable import_positions : (pos,bool ref) PMap.t;
-	mutable dead_blocks : (string,(pos * expr) list) Hashtbl.t;
+	mutable dead_blocks : (Path.UniqueKey.t,(pos * expr) list) Hashtbl.t;
 	mutable unresolved_identifiers : (string * pos * (string * CompletionItem.t * int) list) list;
 	mutable diagnostics_messages : (string * pos * DisplayTypes.DiagnosticsKind.t * DisplayTypes.DiagnosticsSeverity.t) list;
 }

+ 1 - 1
src/context/display/display.ml

@@ -23,7 +23,7 @@ let parse_module ctx m p =
 
 module ReferencePosition = struct
 	let reference_position = ref ("",null_pos,SKOther)
-	let set (s,p,k) = reference_position := (s,{p with pfile = Path.unique_full_path p.pfile},k)
+	let set (s,p,k) = reference_position := (s,{p with pfile = Path.get_full_path p.pfile},k)
 	let get () = !reference_position
 end
 

+ 9 - 8
src/context/display/displayJson.ml

@@ -57,7 +57,7 @@ class display_handler (jsonrpc : jsonrpc_handler) com (cs : CompilationServer.t)
 	method set_display_file was_auto_triggered requires_offset =
 		let file = jsonrpc#get_opt_param (fun () ->
 			let file = jsonrpc#get_string_param "file" in
-			Path.unique_full_path file
+			Path.get_full_path file
 		) DisplayOutput.file_input_marker in
 		let pos = if requires_offset then jsonrpc#get_int_param "offset" else (-1) in
 		TypeloadParse.current_stdin := jsonrpc#get_opt_param (fun () ->
@@ -196,10 +196,11 @@ let handler =
 		);
 		"server/moduleCreated", (fun hctx ->
 			let file = hctx.jsonrpc#get_string_param "file" in
-			let file = Path.unique_full_path file in
+			let file = Path.get_full_path file in
+			let key = Path.UniqueKey.create file in
 			let cs = hctx.display#get_cs in
 			List.iter (fun cc ->
-				Hashtbl.replace cc#get_removed_files file ()
+				Hashtbl.replace cc#get_removed_files key file
 			) cs#get_contexts;
 			hctx.send_result (jstring file);
 		);
@@ -208,9 +209,9 @@ let handler =
 			let cc = hctx.display#get_cs#get_context sign in
 			let files = Hashtbl.fold (fun file cfile acc -> (file,cfile) :: acc) cc#get_files [] in
 			let files = List.sort (fun (file1,_) (file2,_) -> compare file1 file2) files in
-			let files = List.map (fun (file,cfile) ->
+			let files = List.map (fun (fkey,cfile) ->
 				jobject [
-					"file",jstring file;
+					"file",jstring cfile.c_file_path;
 					"time",jfloat cfile.c_time;
 					"pack",jstring (String.concat "." cfile.c_package);
 					"moduleName",jopt jstring cfile.c_module_name;
@@ -220,10 +221,10 @@ let handler =
 		);
 		"server/invalidate", (fun hctx ->
 			let file = hctx.jsonrpc#get_string_param "file" in
-			let file = Path.unique_full_path file in
+			let fkey = Path.UniqueKey.create file in
 			let cs = hctx.display#get_cs in
-			cs#taint_modules file;
-			cs#remove_files file;
+			cs#taint_modules fkey;
+			cs#remove_files fkey;
 			hctx.send_result jnull
 		);
 		"server/configure", (fun hctx ->

+ 4 - 4
src/context/display/displayTexpr.ml

@@ -139,7 +139,7 @@ let check_display_file ctx cs =
 	| Some cc ->
 		begin try
 			let p = DisplayPosition.display_position#get in
-			let cfile = cc#find_file (Path.unique_full_path p.pfile) in
+			let cfile = cc#find_file (Path.UniqueKey.create p.pfile) in
 			let path = (cfile.c_package,get_module_name_of_cfile p.pfile cfile) in
 			TypeloadParse.PdiHandler.handle_pdi ctx.com cfile.c_pdi;
 			(* We have to go through type_module_hook because one of the module's dependencies could be
@@ -150,10 +150,10 @@ let check_display_file ctx cs =
 			end
 		with Not_found ->
 			if ctx.com.display.dms_display then begin
-				let file = (DisplayPosition.display_position#get).pfile in
+				let fkey = DisplayPosition.display_position#get_file_key in
 				(* force parsing again : if the completion point have been changed *)
-				cs#remove_files file;
-				cs#taint_modules file;
+				cs#remove_files fkey;
+				cs#taint_modules fkey;
 			end;
 		end
 	| None ->

+ 9 - 9
src/context/display/displayToplevel.ml

@@ -102,8 +102,8 @@ let read_class_paths com timer =
 			let file,_,pack,_ = Display.parse_module' com path Globals.null_pos in
 			match CompilationServer.get() with
 			| Some cs when pack <> fst path ->
-				let file = Path.unique_full_path file in
-				(CommonCache.get_cache cs com)#remove_file_for_real file
+				let file_key = Path.UniqueKey.create file in
+				(CommonCache.get_cache cs com)#remove_file_for_real file_key
 			| _ ->
 				()
 		end
@@ -124,12 +124,12 @@ let init_or_update_server cs com timer_name =
 		re-parse them and remove them from c_removed_files. *)
 	let removed_files = cc#get_removed_files in
 	let removed_removed_files = DynArray.create () in
-	Hashtbl.iter (fun file () ->
-		DynArray.add removed_removed_files file;
+	Hashtbl.iter (fun file_key file_path ->
+		DynArray.add removed_removed_files file_key;
 		try
-			ignore(cc#find_file file);
+			ignore(cc#find_file file_key);
 		with Not_found ->
-			try ignore(TypeloadParse.parse_module_file com file null_pos) with _ -> ()
+			try ignore(TypeloadParse.parse_module_file com file_path null_pos) with _ -> ()
 	) removed_files;
 	DynArray.iter (Hashtbl.remove removed_files) removed_removed_files
 
@@ -458,8 +458,8 @@ let collect ctx tk with_type sort =
 			| [] -> ()
 			| s :: sl -> add_package (List.rev sl,s)
 		in
-		List.iter (fun ((file,cfile),_) ->
-			let module_name = CompilationServer.get_module_name_of_cfile file cfile in
+		List.iter (fun ((file_key,cfile),_) ->
+			let module_name = CompilationServer.get_module_name_of_cfile cfile.c_file_path cfile in
 			let dot_path = s_type_path (cfile.c_package,module_name) in
 			(* In legacy mode we only show toplevel types. *)
 			if is_legacy_completion && cfile.c_package <> [] then begin
@@ -470,7 +470,7 @@ let collect ctx tk with_type sort =
 			end else if (List.exists (fun e -> ExtString.String.starts_with dot_path (e ^ ".")) !exclude) then
 				()
 			else begin
-				Hashtbl.replace ctx.com.module_to_file (cfile.c_package,module_name) file;
+				Hashtbl.replace ctx.com.module_to_file (cfile.c_package,module_name) cfile.c_file_path;
 				if process_decls cfile.c_package module_name cfile.c_decls then check_package cfile.c_package;
 			end
 		) files;

+ 1 - 1
src/context/display/findReferences.ml

@@ -57,7 +57,7 @@ let collect_reference_positions com =
 				else
 					cf,c
 			in
-			let full_pos p = { p with pfile = Path.unique_full_path p.pfile } in
+			let full_pos p = { p with pfile = Path.get_full_path p.pfile } in
 			if find_descendants then
 				List.fold_left (fun acc t ->
 					match t with

+ 4 - 4
src/context/display/statistics.ml

@@ -22,21 +22,21 @@ let collect_statistics ctx pfilter with_expressions =
 	let relations = Hashtbl.create 0 in
 	let symbols = Hashtbl.create 0 in
 	let handled_modules = Hashtbl.create 0 in
-	let full_path =
+	let path_key =
 		let paths = Hashtbl.create 0 in
 		(fun path ->
 			try
 				Hashtbl.find paths path
 			with Not_found ->
-				let unique = Path.unique_full_path path in
+				let unique = Path.UniqueKey.create path in
 				Hashtbl.add paths path unique;
 				unique
 		)
 	in
 	let check_pos = match pfilter with
 		| SFNone -> (fun p -> p <> null_pos)
-		| SFPos p -> (fun p' -> p.pmin = p'.pmin && p.pmax = p'.pmax && p.pfile = full_path p'.pfile)
-		| SFFile s -> (fun p -> full_path p.pfile = s)
+		| SFPos p -> (fun p' -> p.pmin = p'.pmin && p.pmax = p'.pmax && path_key p.pfile = path_key p'.pfile)
+		| SFFile s -> (fun p -> path_key p.pfile = path_key s)
 	in
 	let add_relation p r =
 		if check_pos p then try

+ 2 - 2
src/context/display/syntaxExplorer.ml

@@ -160,8 +160,8 @@ let explore_uncached_modules tctx cs symbols =
 	let files = cc#get_files in
 	let modules = cc#get_modules in
 	let t = Timer.timer ["display";"references";"candidates"] in
-	let acc = Hashtbl.fold (fun file cfile acc ->
-		let module_name = CompilationServer.get_module_name_of_cfile file cfile in
+	let acc = Hashtbl.fold (fun file_key cfile acc ->
+		let module_name = CompilationServer.get_module_name_of_cfile cfile.CompilationServer.c_file_path cfile in
 		if Hashtbl.mem modules (cfile.c_package,module_name) then
 			acc
 		else try

+ 4 - 3
src/context/typecore.ml

@@ -348,15 +348,16 @@ let exc_protect ?(force=true) ctx f (where:string) =
 
 let fake_modules = Hashtbl.create 0
 let create_fake_module ctx file =
-	let file = Path.unique_full_path file in
-	let mdep = (try Hashtbl.find fake_modules file with Not_found ->
+	let key = Path.UniqueKey.create file in
+	let file = Path.get_full_path file in
+	let mdep = (try Hashtbl.find fake_modules key with Not_found ->
 		let mdep = {
 			m_id = alloc_mid();
 			m_path = (["$DEP"],file);
 			m_types = [];
 			m_extra = module_extra file (Define.get_signature ctx.com.defines) (file_time file) MFake [];
 		} in
-		Hashtbl.add fake_modules file mdep;
+		Hashtbl.add fake_modules key mdep;
 		mdep
 	) in
 	Hashtbl.replace ctx.g.modules mdep.m_path mdep;

+ 18 - 3
src/core/display/displayPosition.ml

@@ -10,6 +10,7 @@ class display_position_container =
 	object (self)
 		(** Current display position *)
 		val mutable pos = null_pos
+		val mutable file_key = None
 		(**
 			Display position value which was set with the latest `display_position#set p` call.
 			Kept even after `display_position#reset` call.
@@ -20,17 +21,29 @@ class display_position_container =
 		*)
 		method set p =
 			pos <- p;
-			last_pos <- p
+			last_pos <- p;
+			file_key <- None
 		(**
 			Get current display position
 		*)
 		method get =
 			pos
+		(**
+			Get current display position
+		*)
+		method get_file_key =
+			match file_key with
+			| None ->
+				let key = Path.UniqueKey.create pos.pfile in
+				file_key <- Some key;
+				key
+			| Some key -> key
 		(**
 			Clears current display position.
 		*)
 		method reset =
-			pos <- null_pos
+			pos <- null_pos;
+			file_key <- None
 		(**
 			Check if `p` contains current display position
 		*)
@@ -40,7 +53,9 @@ class display_position_container =
 			Check if `file` contains current display position
 		*)
 		method is_in_file file =
-			file <> "?" && Path.unique_full_path file = pos.pfile
+			file <> "?"
+			&& pos.pfile <> "?"
+			&& self#get_file_key = Path.UniqueKey.create file
 		(**
 			Cut `p` at the position of the latest `display_position#set pos` call.
 		*)

+ 1 - 1
src/core/displayTypes.ml

@@ -204,7 +204,7 @@ module DisplayMode = struct
 		| DMPackage
 		| DMHover
 		| DMModuleSymbols of string option
-		| DMDiagnostics of string list
+		| DMDiagnostics of Path.UniqueKey.t list
 		| DMStatistics
 		| DMSignature
 

+ 28 - 7
src/core/path.ml

@@ -95,13 +95,34 @@ let get_real_path =
 	else
 		get_full_path
 
-(** Returns absolute path guaranteed to be the same for different letter case.
-    Use where equality comparison is required, lowercases the path on Windows *)
-let unique_full_path =
-	if Globals.is_windows then
-		(fun f -> String.lowercase (get_full_path f))
-	else
-		get_full_path
+module UniqueKey : sig
+	type t
+	(**
+		Returns absolute path guaranteed to be the same for different letter case.
+		Use where equality comparison is required, lowercases the path on Windows
+	*)
+	val create : string -> t
+	(**
+		Check if the first key starts with the second key
+	*)
+	val starts_with : t -> t -> bool
+	(**
+		Get string representation of a key
+	*)
+	val to_string : t -> string
+end = struct
+	type t = string
+	let create =
+		if Globals.is_windows then
+			(fun f -> String.lowercase (get_full_path f))
+		else
+			get_full_path
+
+	let starts_with subj start =
+		ExtString.String.starts_with subj start
+
+	let to_string k = k
+end
 
 let add_trailing_slash p =
 	let l = String.length p in

+ 1 - 1
src/generators/gencs.ml

@@ -3365,7 +3365,7 @@ let generate con =
 				output_string f v;
 				close_out f;
 
-				out_files := (Path.unique_full_path full_path) :: !out_files
+				out_files := (Path.UniqueKey.create full_path) :: !out_files
 			) gen.gcon.resources;
 		end;
 		(* add resources array *)

+ 1 - 1
src/generators/genjava.ml

@@ -2633,7 +2633,7 @@ let generate con =
 		output_string f v;
 		close_out f;
 
-		out_files := (Path.unique_full_path full_path) :: !out_files
+		out_files := (Path.UniqueKey.create full_path) :: !out_files
 	) gen.gcon.resources;
 	(try
 		let c = get_cl (Hashtbl.find gen.gtypes (["haxe"], "Resource")) in

+ 1 - 1
src/macro/eval/evalContext.ml

@@ -414,7 +414,7 @@ let create_env_info static pfile kind capture_infos num_locals num_captures =
 		static = static;
 		kind = kind;
 		pfile = hash pfile;
-		pfile_unique = hash (Path.unique_full_path pfile);
+		pfile_unique = hash (Path.UniqueKey.to_string (Path.UniqueKey.create pfile));
 		capture_infos = capture_infos;
 		num_locals = num_locals;
 		num_captures = num_captures;

+ 2 - 2
src/macro/eval/evalDebugMisc.ml

@@ -43,7 +43,7 @@ let iter_breakpoints ctx f =
 	) ctx.debug.breakpoints
 
 let add_breakpoint ctx file line column condition =
-	let hash = hash (Path.unique_full_path (Common.find_file (ctx.curapi.get_com()) file)) in
+	let hash = hash (Path.UniqueKey.to_string (Path.UniqueKey.create (Common.find_file (ctx.curapi.get_com()) file))) in
 	let h = try
 		Hashtbl.find ctx.debug.breakpoints hash
 	with Not_found ->
@@ -56,7 +56,7 @@ let add_breakpoint ctx file line column condition =
 	breakpoint
 
 let delete_breakpoint ctx file line =
-	let hash = hash (Path.unique_full_path (Common.find_file (ctx.curapi.get_com()) file)) in
+	let hash = hash (Path.UniqueKey.to_string (Path.UniqueKey.create (Common.find_file (ctx.curapi.get_com()) file))) in
 	let h = Hashtbl.find ctx.debug.breakpoints hash in
 	Hashtbl.remove h line
 

+ 1 - 1
src/macro/eval/evalDebugSocket.ml

@@ -630,7 +630,7 @@ let handler =
 			let file = hctx.jsonrpc#get_string_param "file" in
 			let bps = hctx.jsonrpc#get_array_param "breakpoints" in
 			let bps = List.map (parse_breakpoint hctx) bps in
-			let hash = hash (Path.unique_full_path (Common.find_file (hctx.ctx.curapi.get_com()) file)) in
+			let hash = hash (Path.UniqueKey.to_string (Path.UniqueKey.create (Common.find_file (hctx.ctx.curapi.get_com()) file))) in
 			let h =
 				try
 					let h = Hashtbl.find hctx.ctx.debug.breakpoints hash in

+ 2 - 2
src/macro/macroApi.ml

@@ -1526,7 +1526,7 @@ let macro_api ccom get_api =
 				dfile = p.pfile
 				|| (
 					(Filename.is_relative p.pfile || Filename.is_relative dfile)
-					&& (Path.unique_full_path dfile = Path.unique_full_path p.pfile)
+					&& (Path.UniqueKey.create dfile = Path.UniqueKey.create p.pfile)
 				)
 			in
 			vbool (display_pos#enclosed_in p && same_file())
@@ -1928,7 +1928,7 @@ let macro_api ccom get_api =
 			let cs = match CompilationServer.get() with Some cs -> cs | None -> failwith "compilation server not running" in
 			List.iter (fun v ->
 				let s = decode_string v in
-				let s = Path.unique_full_path s in
+				let s = Path.UniqueKey.create s in
 				cs#taint_modules s;
 				cs#remove_files s;
 			) (decode_array a);

+ 1 - 1
src/optimization/dce.ml

@@ -839,7 +839,7 @@ let run com main mode =
 		com = com;
 		full = full;
 		dependent_types = Hashtbl.create 0;
-		std_dirs = if full then [] else List.map Path.unique_full_path com.std_path;
+		std_dirs = if full then [] else List.map Path.get_full_path com.std_path;
 		debug = Common.defined com Define.DceDebug;
 		added_fields = [];
 		follow_expr = expr;

+ 1 - 1
src/syntax/grammar.mly

@@ -1543,7 +1543,7 @@ let rec validate_macro_cond s e = match fst e with
 	| _ -> syntax_error (Custom ("Invalid conditional expression")) ~pos:(Some (pos e)) s ((EConst (Ident "false"),(pos e)))
 
 let parse_macro_ident t p s =
-	if t = "display" then Hashtbl.replace special_identifier_files (Path.unique_full_path p.pfile) t;
+	if t = "display" then Hashtbl.replace special_identifier_files (Path.UniqueKey.create p.pfile) t;
 	let e = (EConst (Ident t),p) in
 	None, e
 

+ 1 - 1
src/syntax/parser.ml

@@ -92,7 +92,7 @@ let syntax_completion kind so p =
 
 let error m p = raise (Error (m,p))
 
-let special_identifier_files : (string,string) Hashtbl.t = Hashtbl.create 0
+let special_identifier_files : (Path.UniqueKey.t,string) Hashtbl.t = Hashtbl.create 0
 
 let decl_flag_to_class_flag (flag,p) = match flag with
 	| DPrivate -> HPrivate

+ 1 - 1
src/syntax/parserEntry.ml

@@ -213,7 +213,7 @@ let parse ctx code file =
 	let old_macro = !in_macro in
 	code_ref := code;
 	in_display := display_position#get <> null_pos;
-	in_display_file := !in_display && Path.unique_full_path file = (display_position#get).pfile;
+	in_display_file := !in_display && display_position#is_in_file file;
 	syntax_errors := [];
 	let restore =
 		(fun () ->

+ 1 - 1
src/typing/typeloadModule.ml

@@ -39,7 +39,7 @@ let make_module ctx mpath file loadp =
 		m_id = alloc_mid();
 		m_path = mpath;
 		m_types = [];
-		m_extra = module_extra (Path.unique_full_path file) (Define.get_signature ctx.com.defines) (file_time file) (if ctx.in_macro then MMacro else MCode) (get_policy ctx mpath);
+		m_extra = module_extra (Path.get_full_path file) (Define.get_signature ctx.com.defines) (file_time file) (if ctx.in_macro then MMacro else MCode) (get_policy ctx mpath);
 	} in
 	m
 

+ 2 - 2
src/typing/typeloadParse.ml

@@ -112,8 +112,8 @@ let resolve_module_file com m remap p =
 	(* if we try to load a std.xxxx class and resolve a real std file, the package name is not valid, ignore *)
 	(match fst m with
 	| "std" :: _ ->
-		let file = Path.unique_full_path file in
-		if List.exists (fun path -> ExtString.String.starts_with file (try Path.unique_full_path path with _ -> path)) com.std_path then raise Not_found;
+		let file_key = Path.UniqueKey.create file in
+		if List.exists (fun path -> Path.UniqueKey.starts_with file_key (Path.UniqueKey.create path)) com.std_path then raise Not_found;
 	| _ -> ());
 	if !forbid then begin
 		let parse_result = (!parse_hook) com file p in

+ 1 - 1
tests/misc/projects/Issue1968/compile.hxml.stderr

@@ -1,3 +1,3 @@
 <list>
-<pos>$$normPath(::cwd::/Main.hx, true):4: characters 28-29</pos>
+<pos>$$normPath(::cwd::/Main.hx):4: characters 28-29</pos>
 </list>

+ 1 - 1
tests/misc/projects/Issue2991/compile.hxml.stderr

@@ -1,3 +1,3 @@
 <list>
-<pos>$$normPath(::cwd::/Main.hx, true):6: characters 13-14</pos>
+<pos>$$normPath(::cwd::/Main.hx):6: characters 13-14</pos>
 </list>

+ 1 - 1
tests/misc/projects/Issue2993/compile.hxml.stderr

@@ -1,3 +1,3 @@
 <list>
-<pos>$$normPath(::cwd::/Main.hx, true):2: characters 16-19</pos>
+<pos>$$normPath(::cwd::/Main.hx):2: characters 16-19</pos>
 </list>

+ 1 - 1
tests/misc/projects/Issue2995/position.hxml.stderr

@@ -1,3 +1,3 @@
 <list>
-<pos>$$normPath(::cwd::/Main.hx, true):2: characters 14-17</pos>
+<pos>$$normPath(::cwd::/Main.hx):2: characters 14-17</pos>
 </list>

+ 2 - 2
tests/misc/projects/Issue2995/usage.hxml.stderr

@@ -1,4 +1,4 @@
 <list>
-<pos>$$normPath(::cwd::/Main.hx, true):5: characters 17-27</pos>
-<pos>$$normPath(::cwd::/Main.hx, true):9: characters 9-19</pos>
+<pos>$$normPath(::cwd::/Main.hx):5: characters 17-27</pos>
+<pos>$$normPath(::cwd::/Main.hx):9: characters 9-19</pos>
 </list>

+ 1 - 1
tests/misc/projects/Issue2996/compile1.hxml.stderr

@@ -1,3 +1,3 @@
 <list>
-<pos>$$normPath(::cwd::/A.hx, true):1: characters 1-22</pos>
+<pos>$$normPath(::cwd::/A.hx):1: characters 1-22</pos>
 </list>

+ 1 - 1
tests/misc/projects/Issue2996/compile2.hxml.stderr

@@ -1,3 +1,3 @@
 <list>
-<pos>$$normPath(::cwd::/pack/B.hx, true):3: characters 1-11</pos>
+<pos>$$normPath(::cwd::/pack/B.hx):3: characters 1-11</pos>
 </list>

+ 1 - 1
tests/misc/projects/Issue2997/compile1.hxml.stderr

@@ -1,3 +1,3 @@
 <list>
-<pos>$$normPath(::cwd::/Main.hx, true):2: characters 9-10</pos>
+<pos>$$normPath(::cwd::/Main.hx):2: characters 9-10</pos>
 </list>

+ 1 - 1
tests/misc/projects/Issue5123/compile.hxml.stderr

@@ -1,3 +1,3 @@
 <list>
-<pos>$$normPath(::cwd::/Main.hx, true):5: characters 18-35</pos>
+<pos>$$normPath(::cwd::/Main.hx):5: characters 18-35</pos>
 </list>

+ 1 - 3
tests/misc/src/Main.hx

@@ -74,13 +74,11 @@ class Main {
 		return new haxe.Template(s).execute(context, macros);
 	}
 
-	static function normPath(_, p:String, properCase = false):String {
+	static function normPath(_, p:String):String {
 		if (Sys.systemName() == "Windows") {
 			// on windows, haxe returns lowercase paths with backslashes, drive letter uppercased
 			p = p.substr(0, 1).toUpperCase() + p.substr(1);
 			p = p.replace("/", "\\");
-			if (!properCase)
-				p = p.toLowerCase();
 		}
 		return p;
 	}

+ 0 - 2
tests/sys/src/TestFileSystem.hx

@@ -146,8 +146,6 @@ class TestFileSystem extends utest.Test {
 			// on windows, haxe returns lowercase paths with backslashes, drive letter uppercased
 			p = p.substr(0, 1).toUpperCase() + p.substr(1);
 			p = p.replace("/", "\\");
-			if (!properCase)
-				p = p.toLowerCase();
 		}
 		return p;
 	}