use of org.codehaus.groovy.ast.Variable in project groovy by apache.
the class StaticTypeCheckingVisitor method storeType.
protected void storeType(Expression exp, ClassNode cn) {
if (exp instanceof VariableExpression && ((VariableExpression) exp).isClosureSharedVariable() && isPrimitiveType(cn)) {
cn = getWrapper(cn);
} else if (exp instanceof MethodCallExpression && ((MethodCallExpression) exp).isSafe() && isPrimitiveType(cn)) {
cn = getWrapper(cn);
} else if (exp instanceof PropertyExpression && ((PropertyExpression) exp).isSafe() && isPrimitiveType(cn)) {
cn = getWrapper(cn);
}
if (cn == UNKNOWN_PARAMETER_TYPE) {
// this can happen for example when "null" is used in an assignment or a method parameter.
// In that case, instead of storing the virtual type, we must "reset" type information
// by determining the declaration type of the expression
storeType(exp, getOriginalDeclarationType(exp));
return;
}
ClassNode oldValue = (ClassNode) exp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, cn);
if (oldValue != null) {
// this may happen when a variable declaration type is wider than the subsequent assignment values
// for example :
// def o = 1 // first, an int
// o = 'String' // then a string
// o = new Object() // and eventually an object !
// in that case, the INFERRED_TYPE corresponds to the current inferred type, while
// DECLARATION_INFERRED_TYPE is the type which should be used for the initial type declaration
ClassNode oldDIT = (ClassNode) exp.getNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE);
if (oldDIT != null) {
exp.putNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE, cn == null ? oldDIT : lowestUpperBound(oldDIT, cn));
} else {
exp.putNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE, cn == null ? null : lowestUpperBound(oldValue, cn));
}
}
if (exp instanceof VariableExpression) {
VariableExpression var = (VariableExpression) exp;
final Variable accessedVariable = var.getAccessedVariable();
if (accessedVariable != null && accessedVariable != exp && accessedVariable instanceof VariableExpression) {
storeType((Expression) accessedVariable, cn);
}
if (var.isClosureSharedVariable() && cn != null) {
List<ClassNode> assignedTypes = typeCheckingContext.closureSharedVariablesAssignmentTypes.get(var);
if (assignedTypes == null) {
assignedTypes = new LinkedList<ClassNode>();
typeCheckingContext.closureSharedVariablesAssignmentTypes.put(var, assignedTypes);
}
assignedTypes.add(cn);
}
if (!typeCheckingContext.temporaryIfBranchTypeInformation.empty()) {
List<ClassNode> temporaryTypesForExpression = getTemporaryTypesForExpression(exp);
if (temporaryTypesForExpression != null && !temporaryTypesForExpression.isEmpty()) {
// a type inference has been made on a variable which type was defined in an instanceof block
// we erase available information with the new type
temporaryTypesForExpression.clear();
}
}
}
}
use of org.codehaus.groovy.ast.Variable in project groovy by apache.
the class BinaryExpressionMultiTypeDispatcher method doAssignmentToLocalVariable.
private boolean doAssignmentToLocalVariable(String method, BinaryExpression binExp) {
Expression left = binExp.getLeftExpression();
if (left instanceof VariableExpression) {
VariableExpression ve = (VariableExpression) left;
Variable v = ve.getAccessedVariable();
if (v instanceof DynamicVariable)
return false;
if (v instanceof PropertyExpression)
return false;
/* field and declaration we don't return false */
} else {
return false;
}
evaluateBinaryExpression(method, binExp);
getController().getOperandStack().dup();
getController().getCompileStack().pushLHS(true);
binExp.getLeftExpression().visit(getController().getAcg());
getController().getCompileStack().popLHS();
return true;
}
use of org.codehaus.groovy.ast.Variable in project groovy by apache.
the class StatementMetaTypeChooser method resolveType.
public ClassNode resolveType(final Expression exp, final ClassNode current) {
if (exp instanceof ClassExpression)
return ClassHelper.CLASS_Type;
OptimizingStatementWriter.StatementMeta meta = (OptimizingStatementWriter.StatementMeta) exp.getNodeMetaData(OptimizingStatementWriter.StatementMeta.class);
ClassNode type = null;
if (meta != null)
type = meta.type;
if (type != null)
return type;
if (exp instanceof VariableExpression) {
VariableExpression ve = (VariableExpression) exp;
if (ve.isClosureSharedVariable())
return ve.getType();
type = ve.getOriginType();
if (ve.getAccessedVariable() instanceof FieldNode) {
FieldNode fn = (FieldNode) ve.getAccessedVariable();
if (!fn.getDeclaringClass().equals(current))
return fn.getOriginType();
}
} else if (exp instanceof Variable) {
Variable v = (Variable) exp;
type = v.getOriginType();
} else {
type = exp.getType();
}
return type.redirect();
}
use of org.codehaus.groovy.ast.Variable in project groovy by apache.
the class ClosureWriter method getClosureSharedVariables.
protected Parameter[] getClosureSharedVariables(ClosureExpression ce) {
VariableScope scope = ce.getVariableScope();
Parameter[] ret = new Parameter[scope.getReferencedLocalVariablesCount()];
int index = 0;
for (Iterator iter = scope.getReferencedLocalVariablesIterator(); iter.hasNext(); ) {
Variable element = (org.codehaus.groovy.ast.Variable) iter.next();
Parameter p = new Parameter(element.getType(), element.getName());
p.setOriginType(element.getOriginType());
p.setClosureSharedVariable(element.isClosureSharedVariable());
ret[index] = p;
index++;
}
return ret;
}
use of org.codehaus.groovy.ast.Variable in project groovy by apache.
the class StaticTypeCheckingVisitor method performSecondPass.
public void performSecondPass() {
for (SecondPassExpression wrapper : typeCheckingContext.secondPassExpressions) {
Expression expression = wrapper.getExpression();
if (expression instanceof BinaryExpression) {
Expression left = ((BinaryExpression) expression).getLeftExpression();
if (left instanceof VariableExpression) {
// should always be the case
// this should always be the case, but adding a test is safer
Variable target = findTargetVariable((VariableExpression) left);
if (target instanceof VariableExpression) {
VariableExpression var = (VariableExpression) target;
List<ClassNode> classNodes = typeCheckingContext.closureSharedVariablesAssignmentTypes.get(var);
if (classNodes != null && classNodes.size() > 1) {
ClassNode lub = lowestUpperBound(classNodes);
String message = getOperationName(((BinaryExpression) expression).getOperation().getType());
if (message != null) {
List<MethodNode> method = findMethod(lub, message, getType(((BinaryExpression) expression).getRightExpression()));
if (method.isEmpty()) {
addStaticTypeError("A closure shared variable [" + target.getName() + "] has been assigned with various types and the method" + " [" + toMethodParametersString(message, getType(((BinaryExpression) expression).getRightExpression())) + "]" + " does not exist in the lowest upper bound of those types: [" + lub.toString(false) + "]. In general, this is a bad practice (variable reuse) because the compiler cannot" + " determine safely what is the type of the variable at the moment of the call in a multithreaded context.", expression);
}
}
}
}
}
} else if (expression instanceof MethodCallExpression) {
MethodCallExpression call = (MethodCallExpression) expression;
Expression objectExpression = call.getObjectExpression();
if (objectExpression instanceof VariableExpression) {
// this should always be the case, but adding a test is safer
Variable target = findTargetVariable((VariableExpression) objectExpression);
if (target instanceof VariableExpression) {
VariableExpression var = (VariableExpression) target;
List<ClassNode> classNodes = typeCheckingContext.closureSharedVariablesAssignmentTypes.get(var);
if (classNodes != null && classNodes.size() > 1) {
ClassNode lub = lowestUpperBound(classNodes);
MethodNode methodNode = (MethodNode) call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
// we must check that such a method exists on the LUB
Parameter[] parameters = methodNode.getParameters();
ClassNode[] params = extractTypesFromParameters(parameters);
ClassNode[] argTypes = (ClassNode[]) wrapper.getData();
List<MethodNode> method = findMethod(lub, methodNode.getName(), argTypes);
if (method.size() != 1) {
addStaticTypeError("A closure shared variable [" + target.getName() + "] has been assigned with various types and the method" + " [" + toMethodParametersString(methodNode.getName(), params) + "]" + " does not exist in the lowest upper bound of those types: [" + lub.toString(false) + "]. In general, this is a bad practice (variable reuse) because the compiler cannot" + " determine safely what is the type of the variable at the moment of the call in a multithreaded context.", call);
}
}
}
}
}
}
// give a chance to type checker extensions to throw errors based on information gathered afterwards
extension.finish();
}
Aggregations