diff options
author | Stephan Herrmann | 2013-01-05 21:46:40 +0000 |
---|---|---|
committer | Stephan Herrmann | 2013-01-22 20:48:26 +0000 |
commit | f347a7c86e66fcbac9468e9bf4d7028a33df1d93 (patch) | |
tree | 76eb6088b195e9323cbfabeeb3103585c120709c | |
parent | 7fbb8f7a2dd267ce2e988aed25ff156cf30c1430 (diff) | |
download | org.eclipse.objectteams-f347a7c86e66fcbac9468e9bf4d7028a33df1d93.tar.gz org.eclipse.objectteams-f347a7c86e66fcbac9468e9bf4d7028a33df1d93.tar.xz org.eclipse.objectteams-f347a7c86e66fcbac9468e9bf4d7028a33df1d93.zip |
Bug 397192 - Prepare OTDT for new (dynamic) weaver:
Improvements for array-translations:
- distinguish who's responsible for lift/lowering: team or current role?
- lift/lower calls are manually resolved, avoid unintended role wrapping
- now some lowering exprs need their teamExpr to be resolved in a
deferred way.
AllTests: 2184/2/135
7 files changed, 142 insertions, 18 deletions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayLifting.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayLifting.java index fd0ac5be5..677ddb03b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayLifting.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayLifting.java @@ -40,7 +40,7 @@ public class ArrayLifting extends ArrayTranslations { TypeBinding requiredType) { this._teamExpr = teamExpr; - return (MessageSend)translateArray(scope, expression, providedType, requiredType, /*isLifting*/true); + return (MessageSend)translateArray(scope, expression, providedType, requiredType, /*isLifting*/true, /*deferredResolve*/false); } /* implement hook. */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayLowering.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayLowering.java index 09edc8aac..6af5828a5 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayLowering.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayLowering.java @@ -44,15 +44,17 @@ public class ArrayLowering extends ArrayTranslations { BlockScope scope, Expression expression, TypeBinding providedType, - TypeBinding requiredType) + TypeBinding requiredType, + boolean deferredResolve) { // TODO (SH): check if we need to use the team anchor of a RoleTypeBinding // as receiver for the translation call. ReferenceBinding teamBinding = ((ReferenceBinding)providedType.leafComponentType()).enclosingType(); if (this._teamExpr == null) this._teamExpr = new AstGenerator(expression).qualifiedThisReference(teamBinding); - this._teamExpr.resolveType(scope); - return translateArray(scope, expression, providedType, requiredType, /*isLifting*/false); + if (!deferredResolve) + this._teamExpr.resolveType(scope); + return translateArray(scope, expression, providedType, requiredType, /*isLifting*/false, deferredResolve); } /* implement hook. */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayTranslations.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayTranslations.java index 60fde271b..5d4966ae4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayTranslations.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/ArrayTranslations.java @@ -36,6 +36,7 @@ import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel; import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstConverter; import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstEdit; import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator; +import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator.IRunInScope; /** * This class handles the common part of array lifting and lowering. @@ -86,20 +87,34 @@ public abstract class ArrayTranslations { * @param providedType given type of expression * @param requiredType this should be produced by translation * @param isLifting is a lifting translation required (else == lowering) + * @param deferredResolve if true we set up a special message send for custom resolving * @return a message send to the appropriate translation method. */ - Expression translateArray(BlockScope scope, Expression expression, TypeBinding providedType, TypeBinding requiredType, boolean isLifting) { + Expression translateArray(BlockScope scope, Expression expression, + TypeBinding providedType, TypeBinding requiredType, + boolean isLifting, boolean deferredResolve) + { this._scope = scope; this._expression = expression; MethodBinding methodBinding = ensureTransformMethod( scope, this._teamExpr, providedType, requiredType, isLifting); + // if expression is resolved but teamExpression is unresolved schedule special resolving: + IRunInScope hook = new IRunInScope() { public void run(BlockScope blockScope) { /*nop*/ } }; + if (deferredResolve && expression.resolvedType != null && this._teamExpr.resolvedType == null) { + hook = new IRunInScope() { public void run(BlockScope blockScope) { + // resolving this expression was deferred: + ArrayTranslations.this._teamExpr.resolve(blockScope); + }}; + } + AstGenerator gen = new AstGenerator(expression.sourceStart, expression.sourceEnd); - MessageSend send = gen.messageSend( + MessageSend send = gen.messageSendWithResolveHook( this._teamExpr, methodBinding.selector, - new Expression[] {expression}); + new Expression[] {expression}, + hook); // manual resolving since expression is already resolved: send.binding = methodBinding; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/Lowering.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/Lowering.java index d332642fa..dcf614610 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/Lowering.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/Lowering.java @@ -74,12 +74,23 @@ public class Lowering implements IOTConstants { * @return translation expression */ public Expression lowerExpression( - BlockScope scope, + final BlockScope scope, final Expression expression, + TypeBinding unloweredType, + TypeBinding requiredType, + final Expression teamExpression, + boolean needNullCheck) + { + return lowerExpression(scope, expression, unloweredType, requiredType, teamExpression, needNullCheck, false); + } + public Expression lowerExpression( + final BlockScope scope, + final Expression expression, TypeBinding unloweredType, TypeBinding requiredType, - Expression teamExpression, - boolean needNullCheck) + final Expression teamExpression, + boolean needNullCheck, + boolean deferredResolve) { // Note, this method is responsible for 'resolving' all AST nodes it generates! @@ -116,7 +127,8 @@ public class Lowering implements IOTConstants { scope, unloweredExpression, unloweredType, - requiredType); + requiredType, + deferredResolve); } else { 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 711ba5b3f..6de35d5c8 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 @@ -38,8 +38,10 @@ import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; @@ -109,7 +111,7 @@ public class CallinImplementorDyn extends MethodMappingImplementor { static final char[] ARGUMENTS = "arguments".toCharArray(); //$NON-NLS-1$ static final char[] _OT_RESULT = "_OT$result".toCharArray(); //$NON-NLS-1$ static final char[] RESULT = "result".toCharArray(); //$NON-NLS-1$ - static final String LOCAL_ROLE = "local$"; //$NON-NLS-1$ + static final String LOCAL_ROLE = "local$role$"; //$NON-NLS-1$ // for call next: private static final char[] BASE_CALL_ARGS = "baseCallArguments".toCharArray(); //$NON-NLS-1$ @@ -596,10 +598,15 @@ public class CallinImplementorDyn extends MethodMappingImplementor { Statement[] messageSendStatements; if (isReplace) { Expression result = roleMethodCall; - if (baseSpec.returnNeedsTranslation) {// FIXME(SH): per base method! + if (baseSpec.returnNeedsTranslation) { // lowering: TypeBinding[]/*role,base*/ returnTypes = getReturnTypes(callinDecl, 0); - result = new Lowering().lowerExpression(methodDecl.scope, result, returnTypes[0], returnTypes[1], gen.thisReference(), true); + // who is responsible for lowering: the team or the current role? + Expression lowerReceiver = (isRoleOfCurrentRole(roleType, returnTypes[0])) + ? gen.singleNameReference(roleVar) + : gen.thisReference(); + result = new Lowering().lowerExpression(methodDecl.scope, result, returnTypes[0], returnTypes[1], + lowerReceiver, true/*needNullCheck*/, true/*delayedResolve*/); } // possibly convert using result mapping callinDecl.checkResultMapping(); @@ -862,8 +869,13 @@ public class CallinImplementorDyn extends MethodMappingImplementor { if (mapping.baseMethodSpecs[0].returnNeedsTranslation) { // FIXME(SH): per basemethod! // lifting: TypeBinding[]/*role,base*/ returnTypes = getReturnTypes(mapping, 0); + // who is responsible for lifting: the team or the current role? + Expression liftReceiver = (isRoleOfCurrentRole(mapping.scope.enclosingReceiverType(), returnTypes[0])) + ? Lifting.liftCall(mapping.scope, gen.thisReference(), gen.singleNameReference(IOTConstants.BASE), returnTypes[1], returnTypes[0], false) + // TODO: might want to extend the signature of callNext to pass the current role to avoid this lifting? + : gen.thisReference(); result = Lifting.liftCall(mapping.scope, - gen.thisReference(), + liftReceiver, gen.castExpression(result, gen.typeReference(returnTypes[1]), CastExpression.RAW), @@ -974,4 +986,40 @@ public class CallinImplementorDyn extends MethodMappingImplementor { } return false; } + + /** + * the expression local$role$n.roleMethod(..) should not wrap its + * return type anchored to the generated team anchor _OT$role, + * because the method should actually be seen as being within + * the scope of this role already, although, physically it is part of + * the team. + * + * @param scope use the scope to determine if we are actually within + * a callin wrapper. + * @param receiver if this is _OT$role this is the role method call. + * @return true if the return type should not be wrapped further. + */ + public static boolean avoidWrapRoleType(BlockScope scope, Expression receiver) { + MethodScope methodScope = scope.methodScope(); + if (methodScope != null) { // CLOVER: never false in jacks suite + AbstractMethodDeclaration refMethod = methodScope.referenceMethod(); + if ( refMethod != null + && refMethod.isMappingWrapper._callin()) + { + if ( receiver instanceof SingleNameReference + && CharOperation.prefixEquals(LOCAL_ROLE.toCharArray(), ((SingleNameReference)receiver).token)) + return true; + } + } + return false; + } + + boolean isRoleOfCurrentRole(ReferenceBinding currentRole, TypeBinding type) { + TypeBinding leafType = type.leafComponentType(); + if (leafType.isRole()) { + return currentRole.erasure().isCompatibleWith(leafType.enclosingType().erasure()); + } + return false; + } + } 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 75dc7ee04..16f5a7c9f 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 @@ -743,6 +743,47 @@ public class AstGenerator extends AstFactory { return messageSend; } + // function type for the next method: + public static interface IRunInScope { void run(BlockScope scope); } + + /** + * Create a message send that has a custom resolve method (see inside for details). + */ + public MessageSend messageSendWithResolveHook(Expression receiver, char[] selector, Expression[] parameters, final IRunInScope hook) { + MessageSend messageSend = new MessageSend() { + @Override + public TypeBinding resolveType(BlockScope scope) { + // arguments always need resolving: + if (this.arguments != null) { + int length = this.arguments.length; + for (int i = 0; i < length; i++){ + Expression argument = this.arguments[i]; + if (argument.resolvedType == null) + argument.resolveType(scope); + } + } + // skip the receiver unless its again a hooked message send: + if (this.receiver.getClass() == this.getClass()) + this.receiver.resolveType(scope); + + // the main payload: + hook.run(scope); + + this.actualReceiverType = this.binding.declaringClass; + return this.resolvedType; + } + }; + messageSend.sourceStart = this.sourceStart; + messageSend.sourceEnd = this.sourceEnd; + messageSend.statementEnd = this.sourceEnd; + messageSend.nameSourcePosition = this.pos; + messageSend.receiver = receiver; + messageSend.selector = selector; + messageSend.arguments = parameters; + messageSend.constant = Constant.NotAConstant; + return messageSend; + } + public MessageSend messageSend(Expression receiver, char[] selector, Expression[] parameters, final TypeBinding resolvedReturn) { MessageSend messageSend = new MessageSend() { @Override diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/RoleTypeCreator.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/RoleTypeCreator.java index 675fc59d1..d59c1991f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/RoleTypeCreator.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/RoleTypeCreator.java @@ -389,9 +389,15 @@ public class RoleTypeCreator implements TagBits { else returnType = roleReturn; } - if (CallinImplementor.avoidWrapRoleType(scope, send.receiver)) - // don't use synthetic _OT$role as additional anchor - return returnType; + if (CallinImplementorDyn.DYNAMIC_WEAVING) { + if (CallinImplementorDyn.avoidWrapRoleType(scope, send.receiver)) + // don't use synthetic local$role$n as additional anchor + return returnType; + } else { + if (CallinImplementor.avoidWrapRoleType(scope, send.receiver)) + // don't use synthetic _OT$role as additional anchor + return returnType; + } } } else { if (send.arguments != null && send.arguments.length > 0) |