Bug 576367 - IllegalAccessError caused by unnecessary cast to
inaccessible type in callout-to-field
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
index a7d8cd3..44353dc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
@@ -614,7 +614,7 @@
 		    		baseAccess = baseSend;
 		    		break;
 				case DYN_ACCESS:
-					baseAccess = CalloutImplementorDyn.baseAccessExpression(calloutDecl.scope, this._role, baseType, receiver, calloutDecl.baseMethodSpec, arguments, gen);
+					baseAccess = CalloutImplementorDyn.baseAccessExpression(calloutDecl.scope, this._role, baseType, receiver, calloutDecl, arguments, gen);
 					break;
     		}
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementorDyn.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementorDyn.java
index 6933f18..b36aa4d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementorDyn.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementorDyn.java
@@ -28,6 +28,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.PotentialLowerExpression;
@@ -49,9 +50,10 @@
 
 
 	public static Expression baseAccessExpression(Scope scope, RoleModel roleModel, ReferenceBinding baseType,
-												  Expression receiver, MethodSpec baseSpec, Expression[] arguments,
+												  Expression receiver, CalloutMappingDeclaration calloutDecl, Expression[] arguments,
 												  AstGenerator gen)
 	{
+		MethodSpec baseSpec = calloutDecl.baseMethodSpec;
 		char[] selector = ensureAccessor(scope, baseType, baseSpec.isStatic()).selector;
 		TeamModel teamModel = roleModel.getTeamModel();
 		TeamModel.UpdatableIntLiteral accessIdArg = gen.updatableIntLiteral(baseSpec.accessId);
@@ -74,8 +76,10 @@
 		MessageSend messageSend = gen.messageSend(receiver, selector, new Expression[] {accessIdArg, opKindArg, packagedArgs, callerArg});
 		if (baseSpec.resolvedType() == TypeBinding.VOID || opKind == 1)
 			return messageSend;
-		else
-			return gen.createCastOrUnboxing(messageSend, baseSpec.resolvedType(), true/*baseAccess*/);
+		TypeBinding expectedType = calloutDecl.mappings != null || calloutDecl.roleMethodSpec.returnNeedsTranslation
+				? baseSpec.resolvedType()
+				: calloutDecl.roleMethodSpec.resolvedType(); // shortcut to avoid casting to an intermediate base type
+		return gen.createCastOrUnboxing(messageSend, expectedType, true/*baseAccess*/);
 	}
 
 	public static MethodBinding ensureAccessor(Scope scope, ReferenceBinding baseType, boolean isStatic) {
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/BaseClassVisibility.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/BaseClassVisibility.java
index 8f025e5..40bd1e4 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/BaseClassVisibility.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/BaseClassVisibility.java
@@ -2232,4 +2232,36 @@
             },
             "Base");
     }
+
+    public void testBug576367() {
+    	runConformTest(new String[] {
+    		"p2/Team576367.java",
+    			"package p2;\n" +
+    			"import java.util.Arrays;\n" +
+    			"import base p1.Base576367;\n" +
+    			"import base p1.Base576367.Inner;\n" +
+    			"public team class Team576367 {\n" +
+    			"	@SuppressWarnings(\"decapsulation\")\n" +
+    			"	protected class R playedBy Base576367 {\n" +
+    			"		public R() { base(); }\n" +
+    			"		public Object[] getInners() -> get Inner[] inners;\n" +
+    			"	}\n" +
+    			"	public static void main(String... args) {\n" +
+    			"		new Team576367().test();\n" +
+    			"	}\n" +
+    			"	void test() {\n" +
+    			"		Object[] os = new R().getInners();\n" +
+    			"		System.out.print(Arrays.toString(os));\n" +
+    			"	}\n" +
+    			"}\n",
+    		"p1/Base576367.java",
+    			"package p1;\n" +
+    			"public class Base576367 {\n" +
+    			"	private Inner[] inners = { new Inner() };\n" +
+    			"	static class Inner {\n" +
+    			"		@Override public String toString() { return \"inner\"; }\n" +
+    			"	}\n" +
+    			"}\n"},
+    		"[inner]");
+    }
 }