Bug 437767 - [java8][null] semantically integrate null type annotations
with anchored role types
- null annotations on LiftingTypeReference
- keep CUScope.originalScope for type annotation resolving
- perform more null analysis for generated code, need the result
  - generate better code that doesn't raise null problems
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
index e4da37c..83b3cd0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
@@ -24,6 +24,7 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.LiftingTypeReference;
 
 /**
  * OTDT changes:
@@ -97,6 +98,10 @@
 				Annotation.isTypeUseCompatible(this.type, scope, this.annotations);
 				scope.validateNullAnnotation(this.binding.tagBits, this.type, this.annotations);
 			}
+//{ObjectTeams: LTR needs to do more work:
+			if (this.type instanceof LiftingTypeReference)
+				((LiftingTypeReference) this.type).updateBindingAndCheckNullness(scope);
+//SH}
 		}
 		this.binding.declaration = this;
 		return this.binding.type; // might have been updated during resolveAnnotations (for typeAnnotations)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
index 9e244bd..c90401a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
@@ -36,7 +36,12 @@
 	public EqualExpression(Expression left, Expression right,int operator) {
 		super(left,right,operator);
 	}
+//{ObjectTeams: made overridable:
+/*orig:
 	private void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
+  :giro */
+	protected void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
+// SH}
 
 		// collect null status of child nodes:
 		int rightStatus = this.right.nullStatus(flowInfo, flowContext);
@@ -193,9 +198,6 @@
 			result = FlowInfo.conditional(result.copy(), result.copy());
 			// TODO (maxime) check, reintroduced copy
 		}
-//{ObjectTeams: no warnings/errors for generated (null-)checks:
-	  if (!this.isGenerated)
-// SH}
 		checkNullComparison(currentScope, flowContext, result, result.initsWhenTrue(), result.initsWhenFalse());
 		return result;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
index 8e7bb3f..7abcefa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
@@ -18,6 +18,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
 import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
 import org.eclipse.jdt.internal.compiler.lookup.Scope;
@@ -82,15 +83,19 @@
 				Scope currentScope = scope;
 				while (currentScope != null) {
 					if (currentScope instanceof OTClassScope) {
-						Scope baseScope = ((OTClassScope)currentScope).getBaseImportScope();
+						CompilationUnitScope baseScope = ((OTClassScope)currentScope).getBaseImportScope(scope);
 						if (baseScope != null) {
-							TypeBinding previousType = this.resolvedType;
-							this.resolvedType = null;
-							TypeBinding baseImportedType = getTypeBinding(baseScope);
-							if (baseImportedType != null && baseImportedType.isValidBinding())
-								return this.resolvedType = baseImportedType;
-							this.resolvedType = previousType;
-							break;
+							try {
+								TypeBinding previousType = this.resolvedType;
+								this.resolvedType = null;
+								TypeBinding baseImportedType = getTypeBinding(baseScope);
+								if (baseImportedType != null && baseImportedType.isValidBinding())
+									return this.resolvedType = baseImportedType;
+								this.resolvedType = previousType;
+								break;
+							} finally {
+								baseScope.originalScope = null;
+							}
 						}
 					}
 					currentScope = currentScope.parent;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
index 24a009a..7556278 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
@@ -252,12 +252,12 @@
 		    }
 		}
 		// find a base import scope if that's allowed:
-	    Scope importScope = null;
+	    CompilationUnitScope importScope = null;
 		if (getBaseclassDecapsulation().isAllowed()) {
 			Scope currentScope = scope;
 			while (currentScope != null) {
 				if (currentScope instanceof OTClassScope) {
-					importScope = ((OTClassScope)currentScope).getBaseImportScope();
+					importScope = ((OTClassScope)currentScope).getBaseImportScope(scope);
 					if (importScope != null)
 						break;
 				}
@@ -268,6 +268,8 @@
 /* orig:
 		TypeBinding type = internalResolveLeafType(scope, enclosingType, checkBounds);
   :giro */
+		if (importScope != null)
+			importScope.originalScope = null;
 // SH}
 
 		// handle three different outcomes:
@@ -553,11 +555,15 @@
 			Scope currentScope = scope;
 			while (currentScope != null) {
 				if (currentScope instanceof OTClassScope) {
-					Scope baseImportScope = ((OTClassScope)currentScope).getBaseImportScope();
+					CompilationUnitScope baseImportScope = ((OTClassScope)currentScope).getBaseImportScope(scope);
 					if (baseImportScope != null) {
-						this.resolvedType = getTypeBinding(baseImportScope);
-						if (this.resolvedType != null && this.resolvedType.isValidBinding())
-							return this.resolvedType = checkResolvedType(this.resolvedType, baseImportScope, location, false);
+						try {
+							this.resolvedType = getTypeBinding(baseImportScope);
+							if (this.resolvedType != null && this.resolvedType.isValidBinding())
+								return this.resolvedType = checkResolvedType(this.resolvedType, baseImportScope, location, false);
+						} finally {
+							baseImportScope.originalScope = null;
+						}
 					}
 				}
 				currentScope = currentScope.parent;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
index 658bc0f..7ee4c81 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
@@ -137,11 +137,15 @@
 			Scope currentScope = scope;
 			while (currentScope != null) {
 				if (currentScope instanceof OTClassScope) {
-					Scope baseImportScope = ((OTClassScope)currentScope).getBaseImportScope();
+					CompilationUnitScope baseImportScope = ((OTClassScope)currentScope).getBaseImportScope(scope);
 					if (baseImportScope != null) {
-						this.resolvedType = getTypeBinding(baseImportScope);
-						if (this.resolvedType != null && this.resolvedType.isValidBinding())
-							return this.resolvedType = checkResolvedType(this.resolvedType, baseImportScope, location, false);
+						try {
+							this.resolvedType = getTypeBinding(baseImportScope);
+							if (this.resolvedType != null && this.resolvedType.isValidBinding())
+								return this.resolvedType = checkResolvedType(this.resolvedType, baseImportScope, location, false);
+						} finally {
+							baseImportScope.originalScope = null;
+						}
 					}
 				}
 				currentScope = currentScope.parent;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
index 0c2295e..2880794 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
@@ -91,6 +91,9 @@
 	private boolean skipCachingImports;
 
 	boolean connectingHierarchy;
+//{ObjectTeams: when used as a baseimport scope, remember the original scope during this current lookup
+	public Scope originalScope;
+// SH}
 
 public CompilationUnitScope(CompilationUnitDeclaration unit, LookupEnvironment environment) {
 	super(COMPILATION_UNIT_SCOPE, null);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index eeb4bb2..9105cb7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -5660,6 +5660,13 @@
 			case Scope.METHOD_SCOPE :
 				resolutionScope = (BlockScope) scope;
 				break;
+//{ObjectTeams: consider baseImportScopes:
+			case Scope.COMPILATION_UNIT_SCOPE:
+				Scope originalScope = ((CompilationUnitScope)scope).originalScope;
+				if (originalScope instanceof BlockScope)
+					return (BlockScope) originalScope;
+				break;
+// SH}
 		}
 		return resolutionScope;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java
index c5bb210..1f43e7d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java
@@ -38,9 +38,9 @@
 import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.LongLiteral;
+import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
 import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
-import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
 import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding;
@@ -206,7 +206,7 @@
 	    			ITeamAnchor anchor = null;
 	    			if (roleRefType.baseclass() instanceof RoleTypeBinding)
 	    				anchor = ((RoleTypeBinding)roleRefType.baseclass())._teamAnchor;
-	    			roleBase = parameterizedRole.environment.createParameterizedType((ReferenceBinding)roleBase.original(), typeArgs, anchor, -1, roleBase.enclosingType(), Binding.NO_ANNOTATIONS);
+	    			roleBase = parameterizedRole.environment.createParameterizedType((ReferenceBinding)roleBase.original(), typeArgs, anchor, -1, roleBase.enclosingType(), roleBase.getTypeAnnotations());
 	    		}
 	    		// THE compatibility check:
 		    	if (   !baseType.isCompatibleWith(roleBase)
@@ -260,6 +260,17 @@
 	    return null;
 	}
 
+	public void updateBindingAndCheckNullness(BlockScope scope) {
+		this.baseReference.resolvedType = this.resolvedType;
+		TypeBinding roleType = this.roleReference.resolvedType;
+		if (roleType != null && roleType.isValidBinding() && scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) {
+	    	NullAnnotationMatching status = NullAnnotationMatching.analyse(roleType, this.resolvedType, -1);
+			if (status.isAnyMismatch()) {
+	    		scope.problemReporter().nullityMismatchingTypeAnnotation(this.fakedArgument.initialization, this.resolvedType, roleType, status);
+	    	}
+		}
+	}
+
 	@Override
 	public char [][] getTypeName() {
 		return this.baseTokens;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/DeclaredLifting.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/DeclaredLifting.java
index afd177b..0e9ff76 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/DeclaredLifting.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/DeclaredLifting.java
@@ -45,6 +45,7 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
 import org.eclipse.jdt.internal.compiler.lookup.MemberTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
@@ -244,9 +245,11 @@
 					ReferenceBinding baseType = null;
 					if (scope.classScope() instanceof OTClassScope) {
 						// try base scope first:
-						Scope baseScope = ((OTClassScope) scope.classScope()).getBaseImportScope();
-						if (baseScope != null)
+						CompilationUnitScope baseScope = ((OTClassScope) scope.classScope()).getBaseImportScope(scope);
+						if (baseScope != null) {
 							baseType = (ReferenceBinding) baseScope.getType(ltr.baseTokens, ltr.baseTokens.length);
+							baseScope.originalScope = null;
+						}
 					} 
 					if (baseType == null || !baseType.isValidBinding())
 						// fall back to normal scope:
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/OTClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/OTClassScope.java
index b990fd4..5c6d287 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/OTClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/OTClassScope.java
@@ -301,7 +301,9 @@
 		this.baseImportScope.topLevelTypes = new SourceTypeBinding[0];
 	}
 
-	public Scope getBaseImportScope() {
+	public CompilationUnitScope getBaseImportScope(Scope originalScope) {
+		if (this.baseImportScope != null)
+			this.baseImportScope.originalScope = originalScope;
 		return this.baseImportScope;
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java
index 858adea..96f5eb2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java
@@ -23,6 +23,7 @@
 import java.util.HashSet;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.Annotation;
 import org.eclipse.jdt.internal.compiler.ast.Argument;
@@ -573,19 +574,23 @@
 	{
 		/*
 		 * For the end of unregisterRole(Object) create:
-		 * 		if (first_cache != null) {
+		 * 		if (first_cache != null && found_base != null) { // ensure no null problems against either variable
 		 * 			first_cache.remove(_OT$base_arg);
 		 *          ((IBoundBase)found_base)._OT$removeRole(_OT$role_arg);
 		 *      }
 		 */
 		return gen.ifStatement(
-					new EqualExpression(
-						gen.singleNameReference(FIRST_CACHE),
-						gen.nullLiteral(),
-						OperatorIds.EQUAL_EQUAL
-					),
-					gen.block(null),
-					gen.block(new Statement[] { // "else" instead of negation
+					new AND_AND_Expression(
+						new EqualExpression(
+							gen.singleNameReference(FIRST_CACHE),
+							gen.nullLiteral(),
+							OperatorIds.NOT_EQUAL),
+						new EqualExpression(
+							gen.singleNameReference(FOUND_BASE),
+							gen.nullLiteral(),
+							OperatorIds.NOT_EQUAL),
+						OperatorIds.AND_AND),
+					gen.block(new Statement[] {
 						gen.messageSend(
 							gen.singleNameReference(FIRST_CACHE),
 							REMOVE,
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java
index de3310a..9b24699 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java
@@ -274,7 +274,11 @@
 		EqualExpression result = new EqualExpression(
 				value,
 				nullLiteral(),
-				OperatorIds.EQUAL_EQUAL);
+				OperatorIds.EQUAL_EQUAL) {
+			protected void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
+				// nop, never warn about generated null checks
+			}
+		};
 		result.sourceStart = this.sourceStart;
 		result.sourceEnd = this.sourceEnd;
 		result.constant = Constant.NotAConstant;
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/AbstractOTJLDNullAnnotationTest.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/AbstractOTJLDNullAnnotationTest.java
index 4abe351..6c45705 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/AbstractOTJLDNullAnnotationTest.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/AbstractOTJLDNullAnnotationTest.java
@@ -211,23 +211,6 @@
 		this.errorMatching = false;
 	}
 
-	/** Relaxed comparison using contains rather than equals. TODO(SH): pattern matching. */
-	protected void checkCompilerLog(String[] testFiles, Requestor requestor,
-			String[] alternatePlatformIndependantExpectedLogs, Throwable exception) {
-		String computedProblemLog = Util.convertToIndependantLineDelimiter(requestor.problemLog.toString());
-		for (String platformIndependantExpectedLog : alternatePlatformIndependantExpectedLogs) {
-			if (computedProblemLog.contains(platformIndependantExpectedLog))
-				return; // OK
-		}
-		logTestTitle();
-		System.out.println(Util.displayString(computedProblemLog, INDENT, SHIFT));
-		logTestFiles(false, testFiles);
-		if (errorMatching && exception == null)
-			fail("Invalid problem log\n"+computedProblemLog);
-		if (!errorMatching && exception == null) {
-			assertEquals("Invalid problem log ", alternatePlatformIndependantExpectedLogs[0], computedProblemLog);
-		}
-    }
 	// inaccessible helper from super
 	void logTestFiles(boolean logTitle, String[] testFiles) {
 		if (logTitle) {
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/OTNullTypeAnnotationTest.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/OTNullTypeAnnotationTest.java
index 2673c85..35c7a58 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/OTNullTypeAnnotationTest.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/OTNullTypeAnnotationTest.java
@@ -31,7 +31,7 @@
 	// Static initializer to specify tests subset using TESTS_* static variables
 	// All specified tests which do not belong to the class are skipped...
 	static {
-//			TESTS_NAMES = new String[] { "testImplicitTeamAnchor1" };
+//			TESTS_NAMES = new String[] { "testLiftingType2" };
 //			TESTS_NUMBERS = new int[] { 561 };
 //			TESTS_RANGE = new int[] { 1, 2049 };
 	}
@@ -102,4 +102,58 @@
 			"----------\n");
 	}
 
+	public void testLiftingType1() {
+		if (this.weavingScheme == WeavingScheme.OTRE) return;
+		runNegativeTestWithLibs(
+			new String[] {
+				"MyTeam.java",
+				"import org.eclipse.jdt.annotation.*;\n" +
+				"public team class MyTeam {\n" +
+				"	protected class MyRole playedBy MyBase {\n" +
+				"		protected void print() {}\n" +
+				"	}\n" +
+				"	void test(@Nullable MyBase as @NonNull MyRole r) {}\n" +
+				"}\n",
+				"MyBase.java",
+				"public class MyBase {}\n"
+			},
+			getCompilerOptions(),
+			"----------\n" + 
+			"1. ERROR in MyTeam.java (at line 6)\n" + 
+			"	void test(@Nullable MyBase as @NonNull MyRole r) {}\n" + 
+			"	                    ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Null type mismatch (type annotations): required \'MyTeam.@NonNull MyRole\' but this expression has type \'@Nullable MyBase\'\n" + 
+			"----------\n");
+	}
+
+	public void testLiftingType2() {
+		if (this.weavingScheme == WeavingScheme.OTRE) return;
+		runNegativeTestWithLibs(
+			new String[] {
+				"MyTeam.java",
+				"import org.eclipse.jdt.annotation.*;\n" +
+				"public team class MyTeam {\n" +
+				"	protected class MyRole playedBy MyBase {\n" +
+				"		protected void print() {}\n" +
+				"	}\n" +
+				"	void test1(MyBase @Nullable[] as MyRole @NonNull[] r) {}\n" +
+				"	void test2(@Nullable MyBase @NonNull[] as @NonNull MyRole @NonNull[] r) {}\n" +
+				"}\n",
+				"MyBase.java",
+				"public class MyBase {}\n"
+			},
+			getCompilerOptions(),
+			"----------\n" + 
+			"1. ERROR in MyTeam.java (at line 6)\n" + 
+			"	void test1(MyBase @Nullable[] as MyRole @NonNull[] r) {}\n" + 
+			"	           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Null type mismatch (type annotations): required \'MyTeam.MyRole @NonNull[]\' but this expression has type \'MyBase @Nullable[]\'\n" + 
+			"----------\n" + 
+			"2. ERROR in MyTeam.java (at line 7)\n" + 
+			"	void test2(@Nullable MyBase @NonNull[] as @NonNull MyRole @NonNull[] r) {}\n" + 
+			"	                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Null type mismatch (type annotations): required \'MyTeam.@NonNull MyRole @NonNull[]\' but this expression has type \'@Nullable MyBase @NonNull[]\'\n" + 
+			"----------\n");
+	}
+
 }