Bug 397182 - Prepare OTDT for new (dynamic) weaver
- fix resolving of type arguments in generated callin wrapper
  - support parameterized qualified type reference from alien scope
  - be more specific what type to use for local variables
  - use erasure only when we absolutely must
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PotentialLiftExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PotentialLiftExpression.java
index 9ebd25f..e6e495f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PotentialLiftExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PotentialLiftExpression.java
@@ -1,7 +1,7 @@
 /**********************************************************************
  * This file is part of "Object Teams Development Tooling"-Software
  *
- * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany,
+ * Copyright 2004, 2014 Fraunhofer Gesellschaft, Munich, Germany,
  * for its Fraunhofer Institute for Computer Architecture and Software
  * Technology (FIRST), Berlin, Germany and Technical University Berlin,
  * Germany.
@@ -10,7 +10,6 @@
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
- * $Id: PotentialLiftExpression.java 23401 2010-02-02 23:56:05Z stephan $
  *
  * Please visit http://www.eclipse.org/objectteams for updates and contact.
  *
@@ -114,11 +113,16 @@
         
         if (this.expectedType == null)
         	this.expectedType = this.expectedTypeReference.resolvedType;
-        this.resolvedType = this.expectedType; // be optimistic.
         this.checked = true;
+        return internalResolveType(scope, providedType, false);
+    }
+
+	// in testOnly mode we avoid error reporting and AST generation, just signal nonnull if lifting is required
+	private TypeBinding internalResolveType(BlockScope scope, TypeBinding providedType, boolean testOnly) {
+		this.resolvedType = this.expectedType; // be optimistic.
         TypeBinding compatibleType = compatibleType(scope, providedType);
         if (compatibleType != null)
-        	return compatibleType;
+        	return testOnly ? null : compatibleType;
 
         TypeBinding roleSideType;
         TypeBinding baseType;
@@ -133,12 +137,12 @@
         }
         ReferenceBinding roleType = null;
         if (!(baseType instanceof ReferenceBinding)) {
-        	return reportIncompatibility(scope, providedType);
+        	return testOnly ? null : reportIncompatibility(scope, providedType);
         } else {
             roleType = (ReferenceBinding)roleSideType;
             if (   !roleType.isDirectRole()
                 || !(baseType instanceof ReferenceBinding))
-            	return reportIncompatibility(scope, providedType);
+            	return testOnly ? null : reportIncompatibility(scope, providedType);
         }
 
         // reset Config, because below we want to check loweringRequired.
@@ -171,6 +175,7 @@
 	        if (   roleType.isHierarchyInconsistent()
 	        	|| roleType.roleModel.hasBaseclassProblem())
 	        {
+	        	if (testOnly) return null;
 	        	// don't install unresolvable liftcall
 	        	scope.problemReporter().referenceContext.tagAsHavingErrors();
 	        	return this.resolvedType;
@@ -180,6 +185,7 @@
         } finally {
         	Config.removeOrRestore(oldConfig, this);
         }
+        if (testOnly) return this.expectedType;
 
         TypeBinding expectedBaseclass = ((ReferenceBinding)this.expectedType.leafComponentType()).baseclass();
         if (this.expectedType.isArrayType())
@@ -228,4 +234,9 @@
 		this.expression = gen.messageSend(this.teamExpr, DeclaredLifting.dynamicLiftSelector(roleType), args);
 		this.resolvedType = this.expression.resolveType(scope); // or resolve bits individually ? (expression is already resolved?)
 	}
+
+	public static boolean isLiftingRequired(BlockScope scope, TypeBinding requiredType, TypeBinding providedType, Expression location) {
+		PotentialLiftExpression ple = new PotentialLiftExpression(null, location, requiredType);
+		return ple.internalResolveType(scope, providedType, true) != null;
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PrivateRoleMethodCall.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PrivateRoleMethodCall.java
index c5546cd..b48332d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PrivateRoleMethodCall.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PrivateRoleMethodCall.java
@@ -1,7 +1,7 @@
 /** 
  * This file is part of "Object Teams Development Tooling"-Software
  * 
- * Copyright 2011 GK Software AG
+ * Copyright 2014 GK Software AG
  * 
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -54,6 +54,7 @@
 		this.isCalloutToField = isCalloutToField;
 		this.gen = gen;
 		this.constant = Constant.NotAConstant;
+		this.nameSourcePosition = gen.pos;
 	}
 
 	@Override
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
index 6cc1a3a..2f850d5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
@@ -436,7 +436,7 @@
 										Lifting.liftCall(callMethod.scope,
 														 gen.thisReference(),
 														 gen.castExpression(gen.baseNameReference(IOTConstants.BASE), 
-																 			gen.baseTypeReference(roleType.baseclass()), 
+																 			gen.alienScopeTypeReference(gen.baseTypeReference(roleType.baseclass()),callinDecl.scope), 
 																 			CastExpression.RAW),
 														 callMethod.scope.getType(IOTConstants.ORG_OBJECTTEAMS_IBOUNDBASE2, 3),
 														 roleType,
@@ -506,6 +506,7 @@
 										roleParam = roleParam.erasure();
 								}
 							}
+							TypeReference localTypeRef = null;
 							if (callinDecl.mappings == null) {
 								arg = gen.arrayReference(gen.singleNameReference(ARGUMENTS), i+baseArgOffset);					//    prepare: somePreparation(arguments[i])
 								TypeBinding baseArgType = baseSpec.resolvedParameters()[i];
@@ -527,17 +528,26 @@
 																	gen.typeReference(baseArgType),
 																	callinDecl.scope),
 															 CastExpression.DO_WRAP);
-									if (!roleParam.leafComponentType().isBaseType()) {
+									if (!roleParam.leafComponentType().isBaseType()
+											&& PotentialLiftExpression.isLiftingRequired(callinDecl.scope, roleParam, baseArgType, arg)) {
 										// lift?(MyBaseClass)
 										Reference liftReceiver = null; // default: let gen find the team
 										if (roleType.isTeam() && TypeBinding.equalsEquals(roleParam.enclosingType(), roleType))
 											liftReceiver = gen.singleNameReference(roleVar); // lift to inner role
 										arg = gen.potentialLift(liftReceiver, arg, roleParam, isReplace/*reversible*/);
+										localTypeRef = gen.typeReference(roleParam);
 										canLiftingFail |= checkLiftingProblem(teamDecl, callinDecl, (ReferenceBinding)roleParam.leafComponentType());
 									}
 								}
+								if (localTypeRef == null)
+									localTypeRef = gen.baseclassReference(baseArgType); // unless lifting was required above
 							} else {
-								arg = getArgument(callinDecl, 														//    prepare:  <mappedArg<n>>
+				 				if (roleParam.isTypeVariable() && ((TypeVariableBinding)roleParam).declaringElement instanceof CallinCalloutBinding)
+				 					localTypeRef = gen.typeReference(roleParam.erasure()); // cannot explicitly mention this TVB
+				 				else
+				 					localTypeRef = gen.typeReference(roleParam);
+								
+				 				arg = getArgument(callinDecl, 														//    prepare:  <mappedArg<n>>
 												  (MethodDeclaration) methodDecl,
 												  callinDecl.getRoleMethod().parameters, 
 												  i+idx,
@@ -563,10 +573,7 @@
 							//            (B): make subsequent blocks share the same local var??
 							// Witness: CallinParameterMapping_LiftingAndLowering.test439_paramMapMultipleBasemethods2()
 			 				char[] localName = (OT_LOCAL+i).toCharArray();											//    RoleParamType _OT$local$n = preparedArg<n>;
-			 				TypeReference roleParamType = gen.typeReference(roleParam);
-			 				if (roleParam.isTypeVariable() && ((TypeVariableBinding)roleParam).declaringElement instanceof CallinCalloutBinding)
-			 					roleParamType = gen.typeReference(roleParam.erasure());
-							blockStatements.add(gen.localVariable(localName, gen.alienScopeTypeReference(roleParamType, callinDecl.scope), arg));
+							blockStatements.add(gen.localVariable(localName, gen.alienScopeTypeReference(localTypeRef, callinDecl.scope), arg));
 							callArgs[i+idx] = gen.singleNameReference(localName);									//    prepare: ... _OT$local$ ...
 	
 						}
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 cefa8c0..556d2a8 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
@@ -1449,6 +1449,9 @@
 			if (original instanceof ArrayQualifiedTypeReference && original.dimensions() > 0) { // could be parameterized type reference
 				ArrayQualifiedTypeReference qTypeRef= (ArrayQualifiedTypeReference)original;
 				result = new AlienScopeArrayQualifiedTypeReference(qTypeRef.tokens, qTypeRef.sourcePositions, qTypeRef.dimensions(), origScope);				
+			} else if (original instanceof ParameterizedQualifiedTypeReference) {
+				ParameterizedQualifiedTypeReference qTypeRef= (ParameterizedQualifiedTypeReference)original;
+				result = new AlienScopeParameterizedQualifiedTypeReference(qTypeRef, origScope);
 			} else {
 				QualifiedTypeReference qTypeRef= (QualifiedTypeReference)original;
 				result = new AlienScopeQualifiedTypeReference(qTypeRef.tokens, qTypeRef.sourcePositions, origScope);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/IAlienScopeTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/IAlienScopeTypeReference.java
index 9e0d26d..576ae62 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/IAlienScopeTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/IAlienScopeTypeReference.java
@@ -1,13 +1,12 @@
 /**********************************************************************
  * This file is part of "Object Teams Development Tooling"-Software
  *
- * Copyright 2008, 2011 Technical University Berlin, Germany.
+ * Copyright 2008, 2014 Technical University Berlin, Germany.
  *
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
- * $Id: IAlienScopeTypeReference.java 23417 2010-02-03 20:13:55Z stephan $
  *
  * Please visit http://www.eclipse.org/objectteams for updates and contact.
  *
@@ -19,6 +18,7 @@
 import org.eclipse.jdt.internal.compiler.CompilationResult.CheckPoint;
 import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
@@ -197,6 +197,46 @@
 		}
 	}
 	
+
+	class AlienScopeParameterizedQualifiedTypeReference extends ParameterizedQualifiedTypeReference implements IAlienScopeTypeReference
+	{
+		Scope alienScope;
+		public AlienScopeParameterizedQualifiedTypeReference(ParameterizedQualifiedTypeReference proto, Scope alienScope) {
+			super(proto.tokens, proto.typeArguments, proto.dimensions(), proto.sourcePositions);
+			this.alienScope = alienScope;
+			this.isGenerated = true; // allow qualified reference to role
+		}
+		public Scope getAlienScope() { return this.alienScope; }
+		@Override
+		public TypeBinding checkResolveUsingBaseImportScope(Scope scope, int location, boolean tolerate) {
+			return super.checkResolveUsingBaseImportScope(this.alienScope, location, tolerate);
+		}
+		@Override
+		public TypeBinding resolveType(ClassScope scope) {
+			TypeDeclaration referenceContext = scope.referenceContext;
+			CheckPoint cp = null;
+			if (referenceContext != null)
+				cp = referenceContext.compilationResult().getCheckPoint(referenceContext);
+			TypeBinding result= super.resolveType(scope);
+			if (result != null && result.isValidBinding())
+				return result;
+			// reset:
+			this.resolvedType = null;
+			if (cp != null && referenceContext != null) // 2. check redundant via correlation
+				referenceContext.compilationResult.rollBack(cp);
+			return super.resolveType(this.alienScope.classScope());
+		}
+		@Override
+		public TypeBinding resolveType(BlockScope scope, boolean checkBounds) {
+			// this variant for use within callin wrappers:
+			return super.resolveType((BlockScope) this.alienScope, checkBounds);
+		}
+		@Override
+		protected void reportDeprecatedPathSyntax(Scope scope) {
+			// no-op, simply suppress this warning.
+		}
+	}
+	
 	
 	class AlienScopeArrayQualifiedTypeReference extends ArrayQualifiedTypeReference implements IAlienScopeTypeReference
 	{
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java
index 0ad5840..e47b1b0 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java
@@ -1,7 +1,7 @@
 /**********************************************************************
  * This file is part of "Object Teams Development Tooling"-Software
  * 
- * Copyright 2010, 2013 Stephan Herrmann
+ * Copyright 2010, 2014 Stephan Herrmann
  * 
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -1386,11 +1386,11 @@
     			"}\n"
     		},
     		"----------\n" + 
-    		"1. ERROR in TeamA12grf16_2.java (at line 4)\n" + 
-    		"	test <- before test;\n" + 
-    		"	^^^^\n" + 
-    		"Type mismatch: cannot convert from String to U\n" + 
-    		"----------\n");
+			"1. ERROR in TeamA12grf16_2.java (at line 4)\n" + 
+			"	test <- before test;\n" + 
+			"	^^^^\n" + 
+			"The method test(U) in the type TeamA12grf16_2<U>.R is not applicable for the arguments (String)\n" + 
+			"----------\n");
     }
 
     // a role does not use the type parameter of its enclosing team, has callin binding