Переглянути джерело

[typer] browse interface fields on extern lib-types

closes #9768
Simon Krajewski 5 роки тому
батько
коміт
18c382b0e7

+ 21 - 2
src/context/display/displayFields.ml

@@ -121,6 +121,19 @@ let collect ctx e_ast e dk with_type p =
 	in
 	let rec loop items t =
 		let is_new_item items name = not (PMap.mem name items) in
+		let rec browse_interfaces c acc =
+			List.fold_left (fun acc (c,tl) ->
+				let acc = List.fold_left (fun acc cf ->
+					if is_new_item acc cf.cf_name then begin
+						let origin = Parent(TClassDecl c) in
+						let item = make_class_field origin cf in
+						PMap.add cf.cf_name item acc
+					end else
+						acc
+				) acc c.cl_ordered_fields in
+				List.fold_left (fun acc (c,_) -> browse_interfaces c acc) acc c.cl_implements
+			) acc c.cl_implements
+		in
 		match follow t with
 		| TMono m ->
 			begin match Monomorph.classify_constraints m with
@@ -145,14 +158,20 @@ let collect ctx e_ast e dk with_type p =
 			(* For classes, browse the hierarchy *)
 			let fields = TClass.get_all_fields c0 tl in
 			Display.merge_core_doc ctx (TClassDecl c0);
-			PMap.foldi (fun k (c,cf) acc ->
+			let acc = PMap.foldi (fun k (c,cf) acc ->
 				if should_access c cf false && is_new_item acc cf.cf_name then begin
 					let origin = if c == c0 then Self(TClassDecl c) else Parent(TClassDecl c) in
 					let item = make_class_field origin cf in
 					PMap.add k item acc
 				end else
 					acc
-			) fields items
+			) fields items in
+			let acc = if has_class_flag c0 CExtern && Meta.has Meta.LibType c0.cl_meta then
+				browse_interfaces c0 acc
+			else
+				acc
+			in
+			acc
 		| TEnum _ ->
 			let t = ctx.g.do_load_type_def ctx p {tpackage=[];tname="EnumValue";tsub=None;tparams=[]} in
 			begin match t with

+ 25 - 2
src/typing/fields.ml

@@ -273,6 +273,23 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 		let f () = type_field_by_et f e (Abstract.get_underlying_type ~return_first:true a tl) in
 		type_field_by_forward f Meta.Forward a
 	in
+	let type_field_by_interfaces c =
+		let rec loop cl = match cl with
+			| [] ->
+				raise Not_found
+			| (ci,tl) :: cl ->
+				begin try
+					let c2, t, f = class_field ctx ci tl i p in
+					let fmode = match c2 with None -> FHAnon | Some (c,tl) -> FHInstance (c,tl) in
+					(* It should be fine to just add the field to our class to make future lookups a bit faster. *)
+					TClass.add_field c f;
+					field_access ctx mode f fmode e p
+				with Not_found ->
+					loop cl
+				end
+		in
+		loop c.cl_implements
+	in
 	let rec type_field_by_type e t =
 		let field_access f fmode = field_access ctx mode f fmode e p in
 		match t with
@@ -288,7 +305,13 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 						| TAbstract _ -> type_field_by_e type_field_by_type (mk_cast e t p);
 						| _ -> raise Not_found
 					) tl
-				| _ -> raise Not_found
+				| _ ->
+					(* For extern lib types we didn't go through check_interfaces and check_abstract_class, which handles some field
+					   generation. We instead do this lazily here by browsing the implemented interfaces (issue #9768). *)
+					if has_class_flag c CExtern && Meta.has Meta.LibType c.cl_meta then
+						type_field_by_interfaces c
+					else
+						raise Not_found
 			)
 		| TAnon a ->
 			(try
@@ -362,7 +385,7 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 			)
 		| _ -> raise Not_found
 	in
-	let rec type_field_by_extension f t e =
+	let type_field_by_extension f t e =
 		let check_constant_struct = ref false in
 		let loop = type_field_by_list (fun (c,pc) ->
 			try

+ 8 - 0
tests/misc/java/projects/Issue9768/Main.hx

@@ -0,0 +1,8 @@
+import java.nio.channels.AsynchronousFileChannel;
+
+class Main {
+	static function main() {
+		var channel:AsynchronousFileChannel = null;
+		channel.close();
+	}
+}

+ 3 - 0
tests/misc/java/projects/Issue9768/compile.hxml

@@ -0,0 +1,3 @@
+-main Main
+--jvm whatever.jar
+--no-output