Browse Source

[typer] automatically add abstract methods from implemented interfaces

Simon Krajewski 5 years ago
parent
commit
68747d7c68

+ 10 - 0
src/core/tOther.ml

@@ -300,6 +300,16 @@ module TClass = struct
 				end
 				end
 		in
 		in
 		loop [] c
 		loop [] c
+
+	let add_field c cf =
+		let is_static = has_class_field_flag cf CfStatic in
+		if is_static then begin
+			c.cl_statics <- PMap.add cf.cf_name cf c.cl_statics;
+			c.cl_ordered_statics <- cf :: c.cl_ordered_statics;
+		end else begin
+			c.cl_fields <- PMap.add cf.cf_name cf c.cl_fields;
+			c.cl_ordered_fields <- cf :: c.cl_ordered_fields;
+		end
 end
 end
 
 
 let s_class_path c =
 let s_class_path c =

+ 11 - 2
src/typing/typeloadCheck.ml

@@ -376,6 +376,15 @@ module Inheritance = struct
 							display_error ctx (compl_msg (error_msg (Unify l))) p;
 							display_error ctx (compl_msg (error_msg (Unify l))) p;
 						end
 						end
 			with
 			with
+				| Not_found when (has_class_flag c CAbstract) ->
+					let cf = {f with cf_overloads = []} in
+					add_class_field_flag cf CfAbstract;
+					begin try
+						let cf' = PMap.find cf.cf_name c.cl_fields in
+						cf'.cf_overloads <- cf :: cf'.cf_overloads
+					with Not_found ->
+						TClass.add_field c cf
+					end
 				| Not_found when not (has_class_flag c CInterface) ->
 				| Not_found when not (has_class_flag c CInterface) ->
 					let msg = if !is_overload then
 					let msg = if !is_overload then
 						let ctx = print_context() in
 						let ctx = print_context() in
@@ -496,7 +505,7 @@ module Inheritance = struct
 					if not (has_class_flag csup CInterface) then error "Cannot extend by using a class" p;
 					if not (has_class_flag csup CInterface) then error "Cannot extend by using a class" p;
 					c.cl_implements <- (csup,params) :: c.cl_implements;
 					c.cl_implements <- (csup,params) :: c.cl_implements;
 					if not !has_interf then begin
 					if not !has_interf then begin
-						if not is_lib then delay ctx PForce (fun() -> check_interfaces ctx c);
+						if not is_lib then delay ctx PConnectField (fun() -> check_interfaces ctx c);
 						has_interf := true;
 						has_interf := true;
 					end
 					end
 				end else begin
 				end else begin
@@ -520,7 +529,7 @@ module Inheritance = struct
 					if not (has_class_flag intf CInterface) then error "You can only implement an interface" p;
 					if not (has_class_flag intf CInterface) then error "You can only implement an interface" p;
 					c.cl_implements <- (intf, params) :: c.cl_implements;
 					c.cl_implements <- (intf, params) :: c.cl_implements;
 					if not !has_interf && not is_lib && not (Meta.has (Meta.Custom "$do_not_check_interf") c.cl_meta) then begin
 					if not !has_interf && not is_lib && not (Meta.has (Meta.Custom "$do_not_check_interf") c.cl_meta) then begin
-						delay ctx PForce (fun() -> check_interfaces ctx c);
+						delay ctx PConnectField (fun() -> check_interfaces ctx c);
 						has_interf := true;
 						has_interf := true;
 					end;
 					end;
 					(fun () ->
 					(fun () ->

+ 1 - 11
src/typing/typeloadFields.ml

@@ -630,16 +630,6 @@ let rec get_parent c name =
 		with
 		with
 			Not_found -> get_parent csup name
 			Not_found -> get_parent csup name
 
 
-let add_field c cf =
-	let is_static = has_class_field_flag cf CfStatic in
-	if is_static then begin
-		c.cl_statics <- PMap.add cf.cf_name cf c.cl_statics;
-		c.cl_ordered_statics <- cf :: c.cl_ordered_statics;
-	end else begin
-		c.cl_fields <- PMap.add cf.cf_name cf c.cl_fields;
-		c.cl_ordered_fields <- cf :: c.cl_ordered_fields;
-	end
-
 let type_opt (ctx,cctx) p t =
 let type_opt (ctx,cctx) p t =
 	let c = cctx.tclass in
 	let c = cctx.tclass in
 	match t with
 	match t with
@@ -1579,7 +1569,7 @@ let init_class ctx c p context_init herits fields =
 						in
 						in
 						display_error ctx ("Duplicate " ^ type_kind ^ " field declaration : " ^ s_type_path path ^ "." ^ cf.cf_name) cf.cf_name_pos
 						display_error ctx ("Duplicate " ^ type_kind ^ " field declaration : " ^ s_type_path path ^ "." ^ cf.cf_name) cf.cf_name_pos
 				else
 				else
-				if fctx.do_add then add_field c cf
+				if fctx.do_add then TClass.add_field c cf
 			end
 			end
 		with Error (Custom str,p2) when p = p2 ->
 		with Error (Custom str,p2) when p = p2 ->
 			display_error ctx str p
 			display_error ctx str p

+ 15 - 0
tests/misc/java/projects/Issue9619/missing-overload-implementation-from-interface/Main.hx

@@ -0,0 +1,15 @@
+interface Interface {
+	@:overload function toBeImplemented():Void;
+	@:overload public function toBeImplemented(i:Int):Void;
+}
+
+@:keep
+abstract class Abstract implements Interface {}
+
+class NotAbstract extends Abstract {}
+
+class Main {
+	static function main() {
+
+	}
+}

+ 3 - 0
tests/misc/java/projects/Issue9619/missing-overload-implementation-from-interface/compile-fail.hxml

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

+ 4 - 0
tests/misc/java/projects/Issue9619/missing-overload-implementation-from-interface/compile-fail.hxml.stderr

@@ -0,0 +1,4 @@
+Main.hx:9: characters 7-18 : This class extends abstract class Abstract but doesn't implement the following methods
+Main.hx:9: characters 7-18 : Implement them or make NotAbstract abstract as well
+Main.hx:3: characters 29-44 : ... toBeImplemented(i:Int)
+Main.hx:2: characters 22-37 : ... toBeImplemented()

+ 42 - 0
tests/unit/src/unit/issues/Issue9619.hx

@@ -24,8 +24,43 @@ private class ConcreteOverloadChild extends AbstractOverloadParent {
 	override function abstractFunction(i:Int):Void {}
 	override function abstractFunction(i:Int):Void {}
 }
 }
 
 
+private interface InterfaceToBeImplemented {
+	@:overload function toBeImplemented():Bool;
+	@:overload public function toBeImplemented(i:Int):Int;
+}
+
+abstract class AbstractThatImplementsInterface implements InterfaceToBeImplemented {
+	public function new() {}
+}
+
+class ConcreteChildThatImplements extends AbstractThatImplementsInterface {
+	@:overload
+	public override function toBeImplemented() {
+		return true;
+	}
+
+	@:overload
+	public override function toBeImplemented(i:Int) {
+		return i * 2;
+	}
+}
+
 #end
 #end
 
 
+private interface InterfaceToBeImplementedNO {
+	function toBeImplemented():Bool;
+}
+
+abstract class AbstractThatImplementsInterfaceNO implements InterfaceToBeImplementedNO {
+	public function new() {}
+}
+
+class ConcreteChildThatImplementsNO extends AbstractThatImplementsInterfaceNO {
+	public override function toBeImplemented() {
+		return true;
+	}
+}
+
 abstract private class AbstractParent {
 abstract private class AbstractParent {
 	public function new():Void {}
 	public function new():Void {}
 
 
@@ -47,6 +82,10 @@ class Issue9619 extends unit.Test {
 		#if (java || cs)
 		#if (java || cs)
 		var cc = new ConcreteOverloadChild();
 		var cc = new ConcreteOverloadChild();
 		t(HelperMacros.typeError(new AbstractOverloadParent()));
 		t(HelperMacros.typeError(new AbstractOverloadParent()));
+
+		var atii:AbstractThatImplementsInterface = new ConcreteChildThatImplements();
+		t(atii.toBeImplemented());
+		eq(24, atii.toBeImplemented(12));
 		#end
 		#end
 		var cc = new ConcreteChild();
 		var cc = new ConcreteChild();
 
 
@@ -55,5 +94,8 @@ class Issue9619 extends unit.Test {
 
 
 		var ac:AbstractParent = cc;
 		var ac:AbstractParent = cc;
 		t(ac.abstractFunction());
 		t(ac.abstractFunction());
+
+		var atiino:AbstractThatImplementsInterfaceNO = new ConcreteChildThatImplementsNO();
+		t(atiino.toBeImplemented());
 	}
 	}
 }
 }