Browse Source

[java] Respect interface methods with Code attributes (#10466)

* [java] respect interface methods with Code attributes

see #10328

* test sub interface
Simon Krajewski 3 years ago
parent
commit
af28c66864

+ 8 - 0
src-json/meta.json

@@ -612,6 +612,14 @@
 		"params": ["Output type package", "Output type name"],
 		"params": ["Output type package", "Output type name"],
 		"targets": ["TClass", "TEnum"]
 		"targets": ["TClass", "TEnum"]
 	},
 	},
+	{
+		"name": "JavaDefault",
+		"metadata": ":java.default",
+		"doc": "Equivalent to the default modifier of the Java language",
+		"platforms": ["java"],
+		"params": [],
+		"targets": ["TClassField"]
+	},
 	{
 	{
 		"name": "JavaNative",
 		"name": "JavaNative",
 		"metadata": ":javaNative",
 		"metadata": ":javaNative",

+ 1 - 0
src/codegen/java.ml

@@ -393,6 +393,7 @@ let convert_java_enum ctx p pe =
 					})
 					})
 				| _ -> error "Method signature was expected" p
 				| _ -> error "Method signature was expected" p
 		in
 		in
+		if field.jf_code <> None && is_interface then cff_meta := (Meta.JavaDefault,[],cff_pos) :: !cff_meta;
 		let cff_name, cff_meta =
 		let cff_name, cff_meta =
 			match String.get cff_name 0 with
 			match String.get cff_name 0 with
 				| '%' ->
 				| '%' ->

+ 2 - 0
src/codegen/javaModern.ml

@@ -789,6 +789,8 @@ module Converter = struct
 						add_access (AOverride,null_pos);
 						add_access (AOverride,null_pos);
 					| _ -> ()
 					| _ -> ()
 				) ann
 				) ann
+			| AttrCode _ when is_interface ->
+				add_meta (Meta.JavaDefault,[],p)
 			| _ -> ()
 			| _ -> ()
 		) jf.jf_attributes;
 		) jf.jf_attributes;
 		let add_native_meta () =
 		let add_native_meta () =

+ 1 - 0
src/core/tType.ml

@@ -406,6 +406,7 @@ type flag_tclass_field =
 	| CfImpl
 	| CfImpl
 	| CfEnum
 	| CfEnum
 	| CfGeneric
 	| CfGeneric
+	| CfDefault (* Interface field with default implementation (only valid on Java) *)
 
 
 type flag_tvar =
 type flag_tvar =
 	| VCaptured
 	| VCaptured

+ 5 - 0
src/generators/genjava.ml

@@ -2093,6 +2093,11 @@ let generate con =
 			newline w
 			newline w
 	in
 	in
 
 
+	let gen_class_field w ?(is_overload=false) is_static cl is_final cf =
+		(* This should probably be handled somewhere earlier in the unholy gencommon machinery, but whatever *)
+		if not (has_class_field_flag cf CfExtern) then gen_class_field w ~is_overload is_static cl is_final cf
+	in
+
 	let gen_class w cl =
 	let gen_class w cl =
 		let cf_filters = [ handle_throws ] in
 		let cf_filters = [ handle_throws ] in
 		List.iter (fun f -> List.iter (f gen) cl.cl_ordered_fields) cf_filters;
 		List.iter (fun f -> List.iter (f gen) cl.cl_ordered_fields) cf_filters;

+ 1 - 1
src/generators/genjvm.ml

@@ -2505,7 +2505,7 @@ class tclass_to_jvm gctx c = object(self)
 		let field mtype cf = match cf.cf_kind with
 		let field mtype cf = match cf.cf_kind with
 			| Method (MethNormal | MethInline) ->
 			| Method (MethNormal | MethInline) ->
 				List.iter (fun cf ->
 				List.iter (fun cf ->
-					self#generate_method gctx jc c mtype cf
+					if not (has_class_field_flag cf CfExtern) then self#generate_method gctx jc c mtype cf
 				) (cf :: List.filter (fun cf -> has_class_field_flag cf CfOverload) cf.cf_overloads)
 				) (cf :: List.filter (fun cf -> has_class_field_flag cf CfOverload) cf.cf_overloads)
 			| _ ->
 			| _ ->
 				if not (has_class_flag c CInterface) && is_physical_field cf then self#generate_field gctx jc c mtype cf
 				if not (has_class_flag c CInterface) && is_physical_field cf then self#generate_field gctx jc c mtype cf

+ 17 - 8
src/typing/typeloadCheck.ml

@@ -353,6 +353,17 @@ module Inheritance = struct
 		let rec check_field i f =
 		let rec check_field i f =
 			let t = (apply_params intf.cl_params params f.cf_type) in
 			let t = (apply_params intf.cl_params params f.cf_type) in
 			let is_overload = ref false in
 			let is_overload = ref false in
+			let make_implicit_field () =
+				let cf = {f with cf_overloads = []} in
+				begin try
+					let cf' = PMap.find cf.cf_name c.cl_fields in
+					Hashtbl.remove ctx.com.overload_cache (c.cl_path,i);
+					cf'.cf_overloads <- cf :: cf'.cf_overloads
+				with Not_found ->
+					TClass.add_field c cf
+				end;
+				cf
+			in
 			try
 			try
 				let map2, t2, f2 = class_field_no_interf c i in
 				let map2, t2, f2 = class_field_no_interf c i in
 				let t2, f2 =
 				let t2, f2 =
@@ -388,15 +399,13 @@ module Inheritance = struct
 				)
 				)
 			with
 			with
 				| Not_found when (has_class_flag c CAbstract) ->
 				| Not_found when (has_class_flag c CAbstract) ->
-					let cf = {f with cf_overloads = []} in
+					let cf = make_implicit_field () in
 					add_class_field_flag cf CfAbstract;
 					add_class_field_flag cf CfAbstract;
-					begin try
-						let cf' = PMap.find cf.cf_name c.cl_fields in
-						Hashtbl.remove ctx.com.overload_cache (c.cl_path,i);
-						cf'.cf_overloads <- cf :: cf'.cf_overloads
-					with Not_found ->
-						TClass.add_field c cf
-					end
+				| Not_found when has_class_field_flag f CfDefault ->
+					let cf = make_implicit_field () in
+					cf.cf_expr <- None;
+					add_class_field_flag cf CfExtern;
+					add_class_field_flag cf CfOverride;
 				| Not_found when not (has_class_flag c CInterface) ->
 				| Not_found when not (has_class_flag c CInterface) ->
 					if Diagnostics.is_diagnostics_run ctx.com c.cl_pos then
 					if Diagnostics.is_diagnostics_run ctx.com c.cl_pos then
 						DynArray.add missing (f,t)
 						DynArray.add missing (f,t)

+ 20 - 0
src/typing/typeloadFields.ml

@@ -66,6 +66,7 @@ type field_init_ctx = {
 	is_inline : bool;
 	is_inline : bool;
 	is_final : bool;
 	is_final : bool;
 	is_static : bool;
 	is_static : bool;
+	default : pos option;
 	override : pos option;
 	override : pos option;
 	overload : pos option;
 	overload : pos option;
 	is_extern : bool;
 	is_extern : bool;
@@ -615,9 +616,16 @@ let create_field_context (ctx,cctx) c cff =
 		| "__init__" when is_static -> FKInit
 		| "__init__" when is_static -> FKInit
 		| _ -> FKNormal
 		| _ -> FKNormal
 	in
 	in
+	let default = try
+		let (_,_,p) = Meta.get Meta.JavaDefault cff.cff_meta in
+		Some p
+	with Not_found ->
+		None
+	in
 	let fctx = {
 	let fctx = {
 		is_inline = is_inline;
 		is_inline = is_inline;
 		is_static = is_static;
 		is_static = is_static;
+		default = default;
 		override = override;
 		override = override;
 		overload = overload;
 		overload = overload;
 		is_macro = is_macro;
 		is_macro = is_macro;
@@ -1261,6 +1269,18 @@ let create_method (ctx,cctx,fctx) c f fd p =
 	end;
 	end;
 	if fctx.is_abstract_member then add_class_field_flag cf CfImpl;
 	if fctx.is_abstract_member then add_class_field_flag cf CfImpl;
 	if fctx.is_generic then add_class_field_flag cf CfGeneric;
 	if fctx.is_generic then add_class_field_flag cf CfGeneric;
+	begin match fctx.default with
+	| Some p ->
+		begin match ctx.com.platform with
+		| Java ->
+			if not (has_class_flag ctx.curclass CExtern) || not (has_class_flag c CInterface) then display_error ctx "The default modifier is only allowed on extern interfaces" p;
+			add_class_field_flag cf CfDefault;
+		| _ ->
+			display_error ctx "The default modifier is only supported on the Java target" p
+		end;
+	| None ->
+		()
+	end;
 	begin match fctx.overload with
 	begin match fctx.overload with
 	| Some p ->
 	| Some p ->
 		if ctx.com.config.pf_overload then
 		if ctx.com.config.pf_overload then

+ 4 - 0
tests/unit/native_java/hxjava_build.txt

@@ -22,4 +22,8 @@ M haxe.UpperCasePackage.SomeClass
 C haxe.UpperCasePackage.SomeClass
 C haxe.UpperCasePackage.SomeClass
 M haxe.UpperCasePackage.lowercase
 M haxe.UpperCasePackage.lowercase
 C haxe.UpperCasePackage.lowercase
 C haxe.UpperCasePackage.lowercase
+M haxe.test.MyDefaultInterface
+C haxe.test.MyDefaultInterface
+M haxe.test.MyDefaultSubInterface
+C haxe.test.MyDefaultSubInterface
 end modules
 end modules

+ 12 - 0
tests/unit/native_java/src/haxe/test/MyDefaultInterface.java

@@ -0,0 +1,12 @@
+package haxe.test;
+import java.lang.annotation.*;
+
+public interface MyDefaultInterface
+{
+	default public String test(String a)
+	{
+		return a.toUpperCase();
+	}
+}
+
+class MyDefaultClass implements MyDefaultInterface {}

+ 7 - 0
tests/unit/native_java/src/haxe/test/MyDefaultSubInterface.java

@@ -0,0 +1,7 @@
+package haxe.test;
+import java.lang.annotation.*;
+
+public interface MyDefaultSubInterface extends MyDefaultInterface
+{
+
+}

+ 99 - 126
tests/unit/src/unit/TestJava.hx

@@ -1,36 +1,40 @@
 package unit;
 package unit;
+
 import haxe.io.Bytes;
 import haxe.io.Bytes;
-import haxe.test.Base;
-import haxe.test.MyClass;
 import haxe.test.Base.Base_InnerClass;
 import haxe.test.Base.Base_InnerClass;
 import haxe.test.Base.Base___InnerClass3__;
 import haxe.test.Base.Base___InnerClass3__;
 import haxe.test.Base.Base___InnerClass3___InnerClass4__;
 import haxe.test.Base.Base___InnerClass3___InnerClass4__;
-import haxe.test.TEnum;
+import haxe.test.Base;
 import haxe.test.LowerCaseClass;
 import haxe.test.LowerCaseClass;
+import haxe.test.MyClass;
+import haxe.test.MyDefaultInterface;
+import haxe.test.MyDefaultSubInterface;
+import haxe.test.TEnum;
 import java.util.EnumSet;
 import java.util.EnumSet;
 import java.vm.*;
 import java.vm.*;
 
 
 #if java
 #if java
-@:strict(haxe.test.MyClass.MyClass_MyAnnotation({ author:"John Doe", someEnum: TB }))
+@:strict(haxe.test.MyClass.MyClass_MyAnnotation({author: "John Doe", someEnum: TB}))
 @:strict(MyClass_ParameterLessAnnotation)
 @:strict(MyClass_ParameterLessAnnotation)
-class TestJava extends Test
-{
-  function testException()
-  {
-	var native = new NativeClass();
-	var hx:NativeClass = new HxClass();
-
-	exc(function() try native.excTest() catch (e:Dynamic) throw e);
-	var dyn:Dynamic = native;
-	exc(dyn.excTest);
-
-	try
-	  hx.excTest()
-	catch(e:Dynamic) throw e; //shouldn't throw any exception
-  }
-
-	public function testIssue2964()
-	{
+class TestJava extends Test {
+	function testException() {
+		var native = new NativeClass();
+		var hx:NativeClass = new HxClass();
+
+		exc(function() try
+			native.excTest()
+		catch (e:Dynamic)
+			throw e);
+		var dyn:Dynamic = native;
+		exc(dyn.excTest);
+
+		try
+			hx.excTest()
+		catch (e:Dynamic)
+			throw e; // shouldn't throw any exception
+	}
+
+	public function testIssue2964() {
 		var cl = new MyClass();
 		var cl = new MyClass();
 		var bbool:java.lang.Boolean = null;
 		var bbool:java.lang.Boolean = null;
 		eq(cl.boolTest1(bbool), 100);
 		eq(cl.boolTest1(bbool), 100);
@@ -46,42 +50,40 @@ class TestJava extends Test
 
 
 		var i:java.lang.Integer = null;
 		var i:java.lang.Integer = null;
 		eq(cl.intTest1(i), 100);
 		eq(cl.intTest1(i), 100);
-		eq(cl.intTest1(cast(-1, java.lang.Integer)),-1);
-		eq(cl.intTest1(cast(1000, java.lang.Integer)),1000);
+		eq(cl.intTest1(cast(-1, java.lang.Integer)), -1);
+		eq(cl.intTest1(cast(1000, java.lang.Integer)), 1000);
 		i = -1;
 		i = -1;
 		eq(cl.intTest1(i), -1);
 		eq(cl.intTest1(i), -1);
 		i = null;
 		i = null;
 		eq(cl.intTest2(i), 100);
 		eq(cl.intTest2(i), 100);
-		eq(cl.intTest2(-1),-1);
-		eq(cl.intTest2(1000),1000);
+		eq(cl.intTest2(-1), -1);
+		eq(cl.intTest2(1000), 1000);
 		i = -1;
 		i = -1;
 		eq(cl.intTest2(i), -1);
 		eq(cl.intTest2(i), -1);
 
 
 		var i:java.lang.Long = null;
 		var i:java.lang.Long = null;
 		eq(cl.longTest(i), 100);
 		eq(cl.longTest(i), 100);
-		eq(cl.longTest(haxe.Int64.ofInt(-1)),-1);
-		eq(cl.longTest(haxe.Int64.ofInt(1000)),1000);
+		eq(cl.longTest(haxe.Int64.ofInt(-1)), -1);
+		eq(cl.longTest(haxe.Int64.ofInt(1000)), 1000);
 		i = 10;
 		i = 10;
 		eq(cl.longTest(i), 10);
 		eq(cl.longTest(i), 10);
 	}
 	}
 
 
-	public function testVarClash()
-	{
+	public function testVarClash() {
 		var ic = new Base_InnerClass2();
 		var ic = new Base_InnerClass2();
 		eq(ic.varNameClash2(), 1);
 		eq(ic.varNameClash2(), 1);
-		eq(ic.varNameClash2(2),2.2);
+		eq(ic.varNameClash2(2), 2.2);
 		var iface:Base_VarNameClash = ic;
 		var iface:Base_VarNameClash = ic;
 		eq(iface.varNameClash2(), 1);
 		eq(iface.varNameClash2(), 1);
-		eq(iface.varNameClash2(2),2.2);
+		eq(iface.varNameClash2(2), 2.2);
 		var base:Base = ic;
 		var base:Base = ic;
-		eq(base.varNameClash2,0);
+		eq(base.varNameClash2, 0);
 		base.varNameClash2 = 2;
 		base.varNameClash2 = 2;
-		eq(base.varNameClash2,2);
+		eq(base.varNameClash2, 2);
 	}
 	}
 
 
-	@:strict(MyClass_MyAnnotation({ author:"author", currentRevision: 2 }))
-	public function testAnnotations()
-	{
+	@:strict(MyClass_MyAnnotation({author: "author", currentRevision: 2}))
+	public function testAnnotations() {
 		var cl = java.Lib.toNativeType(TestJava);
 		var cl = java.Lib.toNativeType(TestJava);
 		var a = cl.getAnnotation(java.Lib.toNativeType(MyClass_MyAnnotation));
 		var a = cl.getAnnotation(java.Lib.toNativeType(MyClass_MyAnnotation));
 		t(a != null);
 		t(a != null);
@@ -97,20 +99,17 @@ class TestJava extends Test
 		eq(a.currentRevision(), 2);
 		eq(a.currentRevision(), 2);
 	}
 	}
 
 
-	function testLowerCase()
-	{
+	function testLowerCase() {
 		var l = new LowerCaseClass();
 		var l = new LowerCaseClass();
 		t(l.works);
 		t(l.works);
 	}
 	}
 
 
-	function testNameCase()
-	{
+	function testNameCase() {
 		t(haxe.uppercasepackage.SomeClass.SomeClassFound);
 		t(haxe.uppercasepackage.SomeClass.SomeClassFound);
 		t(haxe.uppercasepackage.Lowercase.lowercaseFound);
 		t(haxe.uppercasepackage.Lowercase.lowercaseFound);
 	}
 	}
 
 
-	function testEnumSet()
-	{
+	function testEnumSet() {
 		var es1:EnumSet<TEnum> = EnumSet.noneOf(java.Lib.toNativeEnum(TEnum));
 		var es1:EnumSet<TEnum> = EnumSet.noneOf(java.Lib.toNativeEnum(TEnum));
 		f(es1.contains(TA));
 		f(es1.contains(TA));
 		es1.add(TA);
 		es1.add(TA);
@@ -121,8 +120,7 @@ class TestJava extends Test
 		// f(es2.contains(HC));
 		// f(es2.contains(HC));
 	}
 	}
 
 
-	function testHaxeKeywords()
-	{
+	function testHaxeKeywords() {
 		eq(Base._inline, 42);
 		eq(Base._inline, 42);
 		eq(Base.callback, 43);
 		eq(Base.callback, 43);
 		eq(Base._cast, 44);
 		eq(Base._cast, 44);
@@ -132,15 +130,12 @@ class TestJava extends Test
 		eq(Base._in, 40);
 		eq(Base._in, 40);
 	}
 	}
 
 
-	function testTypes()
-	{
+	function testTypes() {
 		eq(Base.charTest(cast 10), cast 10);
 		eq(Base.charTest(cast 10), cast 10);
 		eq(Base.byteTest(cast 10), cast 10);
 		eq(Base.byteTest(cast 10), cast 10);
 	}
 	}
 
 
-
-	function testInnerClass()
-	{
+	function testInnerClass() {
 		//-java-lib should be able to detect inner classes on import
 		//-java-lib should be able to detect inner classes on import
 		var i = new Base_InnerClass();
 		var i = new Base_InnerClass();
 		eq(i.nameClash(), 10);
 		eq(i.nameClash(), 10);
@@ -158,13 +153,12 @@ class TestJava extends Test
 		eq("$$Inner$$Name8", haxe.test.MyClass.MyClass___Inner__Name7_____Inner__Name8.test());
 		eq("$$Inner$$Name8", haxe.test.MyClass.MyClass___Inner__Name7_____Inner__Name8.test());
 	}
 	}
 
 
-	function testGenerics()
-	{
+	function testGenerics() {
 		var jcl:java.lang.Class<Base_InnerClass_InnerInnerClass> = cast Base_InnerClass_InnerInnerClass;
 		var jcl:java.lang.Class<Base_InnerClass_InnerInnerClass> = cast Base_InnerClass_InnerInnerClass;
 		t(haxe.test.GenericHelper.staticTypedGeneric(jcl) != null);
 		t(haxe.test.GenericHelper.staticTypedGeneric(jcl) != null);
 
 
 		var helper = new haxe.test.GenericHelper();
 		var helper = new haxe.test.GenericHelper();
-		//TODO use typedAs
+		// TODO use typedAs
 		eq(helper.getUntypedGeneric(), null);
 		eq(helper.getUntypedGeneric(), null);
 		eq(helper.typedGeneric, null);
 		eq(helper.typedGeneric, null);
 
 
@@ -172,21 +166,18 @@ class TestJava extends Test
 		var val3 = new Base___InnerClass3__();
 		var val3 = new Base___InnerClass3__();
 		var g1 = new haxe.test.Generic1(val);
 		var g1 = new haxe.test.Generic1(val);
 		g1.complexTypeParameterOfTypeParameter(new Base_InnerClass_InnerInnerClass());
 		g1.complexTypeParameterOfTypeParameter(new Base_InnerClass_InnerInnerClass());
-		//if no compile-time error, we're fine!
+		// if no compile-time error, we're fine!
 		t(true);
 		t(true);
 	}
 	}
 
 
-	function testNameClash()
-	{
+	function testNameClash() {
 		eq(Base.nameClash(null), -1);
 		eq(Base.nameClash(null), -1);
 		eq(new Base().nameClash(), 1);
 		eq(new Base().nameClash(), 1);
 		eq(new Base().varNameClash(1), 1);
 		eq(new Base().varNameClash(1), 1);
 		eq(Base.varNameClash(10.4), 10.4);
 		eq(Base.varNameClash(10.4), 10.4);
-
 	}
 	}
 
 
-	function testOverloadOverride()
-	{
+	function testOverloadOverride() {
 		var c = new TestMyClass();
 		var c = new TestMyClass();
 		c.normalOverload(true);
 		c.normalOverload(true);
 		t(c.boolCalled);
 		t(c.boolCalled);
@@ -214,8 +205,7 @@ class TestJava extends Test
 		t(c.dynamicCalled);
 		t(c.dynamicCalled);
 	}
 	}
 
 
-	function testThrows1()
-	{
+	function testThrows1() {
 		// test 1: no @:throws / no catch
 		// test 1: no @:throws / no catch
 		var b = new Base();
 		var b = new Base();
 		eq(Base.throwsTest(), 5);
 		eq(Base.throwsTest(), 5);
@@ -224,49 +214,37 @@ class TestJava extends Test
 		eq(b.throwsMemberTest(true), 10);
 		eq(b.throwsMemberTest(true), 10);
 	}
 	}
 
 
-	function testThrows2()
-	{
+	function testThrows2() {
 		// test 2: catching only the IOException
 		// test 2: catching only the IOException
-		try
-		{
+		try {
 			var b = new Base();
 			var b = new Base();
 			eq(Base.throwsTest(), 5);
 			eq(Base.throwsTest(), 5);
 			eq(Base.throwsTest(42), 42);
 			eq(Base.throwsTest(42), 42);
 			eq(b.throwsMemberTest(), 6);
 			eq(b.throwsMemberTest(), 6);
 			eq(b.throwsMemberTest(true), 10);
 			eq(b.throwsMemberTest(true), 10);
-		}
-		catch(e:java.io.IOException)
-		{
-		}
+		} catch (e:java.io.IOException) {}
 	}
 	}
 
 
-	function testThrows3()
-	{
+	function testThrows3() {
 		// test 3: catching all exceptions
 		// test 3: catching all exceptions
-		try
-		{
+		try {
 			var b = new Base();
 			var b = new Base();
 			eq(Base.throwsTest(), 5);
 			eq(Base.throwsTest(), 5);
 			eq(Base.throwsTest(42), 42);
 			eq(Base.throwsTest(42), 42);
 			eq(b.throwsMemberTest(), 6);
 			eq(b.throwsMemberTest(), 6);
 			eq(b.throwsMemberTest(true), 10);
 			eq(b.throwsMemberTest(true), 10);
-		}
-		catch(e:java.lang.Throwable)
-		{
-		}
+		} catch (e:java.lang.Throwable) {}
 	}
 	}
 
 
 	// test 4: @:throws IOException and only use IOException
 	// test 4: @:throws IOException and only use IOException
-	@:throws('java.io.IOException') function testThrows4()
-	{
+	@:throws('java.io.IOException') function testThrows4() {
 		var b = new Base();
 		var b = new Base();
 		eq(Base.throwsTest(), 5);
 		eq(Base.throwsTest(), 5);
 		eq(b.throwsMemberTest(true), 10);
 		eq(b.throwsMemberTest(true), 10);
 	}
 	}
 
 
 	// test 5: @:throws IOException and use any
 	// test 5: @:throws IOException and use any
-	@:throws('java.io.IOException') function testThrows5()
-	{
+	@:throws('java.io.IOException') function testThrows5() {
 		var b = new Base();
 		var b = new Base();
 		eq(Base.throwsTest(), 5);
 		eq(Base.throwsTest(), 5);
 		eq(Base.throwsTest(42), 42);
 		eq(Base.throwsTest(42), 42);
@@ -274,39 +252,42 @@ class TestJava extends Test
 		eq(b.throwsMemberTest(true), 10);
 		eq(b.throwsMemberTest(true), 10);
 	}
 	}
 
 
-	function testJavaLibEnum()
-	{
+	function testJavaLibEnum() {
 		var e = TEnum.TA;
 		var e = TEnum.TA;
-		switch(e)
-		{
+		switch (e) {
 			case TA:
 			case TA:
 				t(true);
 				t(true);
 			case _:
 			case _:
 				t(false);
 				t(false);
 		}
 		}
-		eq("TA",Type.enumConstructor(e));
+		eq("TA", Type.enumConstructor(e));
 	}
 	}
 
 
-	function testMiscJavaLib()
-	{
-		//setting inline should be an error
+	function testMiscJavaLib() {
+		// setting inline should be an error
 		t(HelperMacros.typeError(Base.inlineNumber = 4));
 		t(HelperMacros.typeError(Base.inlineNumber = 4));
 	}
 	}
 
 
-	//TODO:
-	//overload with functions + variable types
+	// TODO:
+	// overload with functions + variable types
 
 
+	function testDefaultInterface() {
+		var c = new MyDefaultInterfaceClass();
+		eq("FOO", c.test("foo"));
+	}
+
+	function testDefaultSubInterface() {
+		var c = new MyDefaultSubInterfaceClass();
+		eq("FOO", c.test("foo"));
+	}
 }
 }
 
 
-private class TestMyClass extends haxe.test.MyClass
-{
-	@:overload public function new()
-	{
+private class TestMyClass extends haxe.test.MyClass {
+	@:overload public function new() {
 		super();
 		super();
 	}
 	}
 
 
-	@:overload public function new(str:String)
-	{
+	@:overload public function new(str:String) {
 		super();
 		super();
 		alternativeCtorCalled = true;
 		alternativeCtorCalled = true;
 	}
 	}
@@ -318,54 +299,39 @@ private class TestMyClass extends haxe.test.MyClass
 	public var stringCalled:Bool;
 	public var stringCalled:Bool;
 	public var dynamicCalled:Bool;
 	public var dynamicCalled:Bool;
 
 
-	@:overload override public function normalOverload(b:Bool):Void
-	{
+	@:overload override public function normalOverload(b:Bool):Void {
 		this.boolCalled = true;
 		this.boolCalled = true;
 	}
 	}
 
 
-	@:overload override public function normalOverload(i:Int):Void
-	{
+	@:overload override public function normalOverload(i:Int):Void {
 		this.intCalled = true;
 		this.intCalled = true;
 	}
 	}
 
 
-	@:overload override public function normalOverload(i64:haxe.Int64):Void
-	{
+	@:overload override public function normalOverload(i64:haxe.Int64):Void {
 		this.int64Called = true;
 		this.int64Called = true;
 	}
 	}
 
 
-	@:overload override public function normalOverload(str:String):Void
-	{
+	@:overload override public function normalOverload(str:String):Void {
 		this.stringCalled = true;
 		this.stringCalled = true;
 	}
 	}
 
 
-	@:overload override public function normalOverload(dyn:Dynamic):Void
-	{
+	@:overload override public function normalOverload(dyn:Dynamic):Void {
 		this.dynamicCalled = true;
 		this.dynamicCalled = true;
 	}
 	}
 }
 }
 
 
-@:nativeGen private class NativeClass
-{
-  public function new()
-  {
+@:nativeGen private class NativeClass {
+	public function new() {}
 
 
-  }
-
-  @:throws("java.lang.Throwable")
-  public function excTest():Void
-  {
-	throw new java.lang.Throwable("test", null);
-  }
+	@:throws("java.lang.Throwable")
+	public function excTest():Void {
+		throw new java.lang.Throwable("test", null);
+	}
 }
 }
 
 
-private class HxClass extends NativeClass
-{
-
-  @:throws("java.lang.Throwable")
-  override public function excTest():Void
-  {
-
-  }
+private class HxClass extends NativeClass {
+	@:throws("java.lang.Throwable")
+	override public function excTest():Void {}
 }
 }
 
 
 enum HaxeEnum {
 enum HaxeEnum {
@@ -374,4 +340,11 @@ enum HaxeEnum {
 	HC;
 	HC;
 }
 }
 
 
+class MyDefaultInterfaceClass implements MyDefaultInterface {
+	public function new() {}
+}
+
+class MyDefaultSubInterfaceClass implements MyDefaultSubInterface {
+	public function new() {}
+}
 #end
 #end