Index: dart/compiler/java/com/google/dart/compiler/backend/common/TypeHeuristicImplementation.java |
diff --git a/dart/compiler/java/com/google/dart/compiler/backend/common/TypeHeuristicImplementation.java b/dart/compiler/java/com/google/dart/compiler/backend/common/TypeHeuristicImplementation.java |
deleted file mode 100644 |
index 53e46b344c5330a6e5321be83112b96e9a5ec7e4..0000000000000000000000000000000000000000 |
--- a/dart/compiler/java/com/google/dart/compiler/backend/common/TypeHeuristicImplementation.java |
+++ /dev/null |
@@ -1,1161 +0,0 @@ |
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-package com.google.dart.compiler.backend.common; |
- |
-import com.google.common.collect.Sets; |
-import com.google.dart.compiler.ast.DartArrayAccess; |
-import com.google.dart.compiler.ast.DartArrayLiteral; |
-import com.google.dart.compiler.ast.DartAssertion; |
-import com.google.dart.compiler.ast.DartBinaryExpression; |
-import com.google.dart.compiler.ast.DartBlock; |
-import com.google.dart.compiler.ast.DartBooleanLiteral; |
-import com.google.dart.compiler.ast.DartBreakStatement; |
-import com.google.dart.compiler.ast.DartCase; |
-import com.google.dart.compiler.ast.DartCatchBlock; |
-import com.google.dart.compiler.ast.DartClass; |
-import com.google.dart.compiler.ast.DartConditional; |
-import com.google.dart.compiler.ast.DartContinueStatement; |
-import com.google.dart.compiler.ast.DartDefault; |
-import com.google.dart.compiler.ast.DartDoWhileStatement; |
-import com.google.dart.compiler.ast.DartDoubleLiteral; |
-import com.google.dart.compiler.ast.DartEmptyStatement; |
-import com.google.dart.compiler.ast.DartExprStmt; |
-import com.google.dart.compiler.ast.DartExpression; |
-import com.google.dart.compiler.ast.DartField; |
-import com.google.dart.compiler.ast.DartFieldDefinition; |
-import com.google.dart.compiler.ast.DartForInStatement; |
-import com.google.dart.compiler.ast.DartForStatement; |
-import com.google.dart.compiler.ast.DartFunction; |
-import com.google.dart.compiler.ast.DartFunctionExpression; |
-import com.google.dart.compiler.ast.DartFunctionObjectInvocation; |
-import com.google.dart.compiler.ast.DartFunctionTypeAlias; |
-import com.google.dart.compiler.ast.DartIdentifier; |
-import com.google.dart.compiler.ast.DartIfStatement; |
-import com.google.dart.compiler.ast.DartImportDirective; |
-import com.google.dart.compiler.ast.DartInitializer; |
-import com.google.dart.compiler.ast.DartIntegerLiteral; |
-import com.google.dart.compiler.ast.DartLabel; |
-import com.google.dart.compiler.ast.DartLibraryDirective; |
-import com.google.dart.compiler.ast.DartLiteral; |
-import com.google.dart.compiler.ast.DartMapLiteral; |
-import com.google.dart.compiler.ast.DartMapLiteralEntry; |
-import com.google.dart.compiler.ast.DartMethodDefinition; |
-import com.google.dart.compiler.ast.DartMethodInvocation; |
-import com.google.dart.compiler.ast.DartNamedExpression; |
-import com.google.dart.compiler.ast.DartNativeBlock; |
-import com.google.dart.compiler.ast.DartNativeDirective; |
-import com.google.dart.compiler.ast.DartNewExpression; |
-import com.google.dart.compiler.ast.DartNode; |
-import com.google.dart.compiler.ast.DartNullLiteral; |
-import com.google.dart.compiler.ast.DartParameter; |
-import com.google.dart.compiler.ast.DartParameterizedTypeNode; |
-import com.google.dart.compiler.ast.DartParenthesizedExpression; |
-import com.google.dart.compiler.ast.DartPlainVisitor; |
-import com.google.dart.compiler.ast.DartPropertyAccess; |
-import com.google.dart.compiler.ast.DartRedirectConstructorInvocation; |
-import com.google.dart.compiler.ast.DartResourceDirective; |
-import com.google.dart.compiler.ast.DartReturnStatement; |
-import com.google.dart.compiler.ast.DartSourceDirective; |
-import com.google.dart.compiler.ast.DartStringInterpolation; |
-import com.google.dart.compiler.ast.DartStringLiteral; |
-import com.google.dart.compiler.ast.DartSuperConstructorInvocation; |
-import com.google.dart.compiler.ast.DartSuperExpression; |
-import com.google.dart.compiler.ast.DartSwitchStatement; |
-import com.google.dart.compiler.ast.DartSyntheticErrorExpression; |
-import com.google.dart.compiler.ast.DartSyntheticErrorStatement; |
-import com.google.dart.compiler.ast.DartThisExpression; |
-import com.google.dart.compiler.ast.DartThrowStatement; |
-import com.google.dart.compiler.ast.DartTryStatement; |
-import com.google.dart.compiler.ast.DartTypeExpression; |
-import com.google.dart.compiler.ast.DartTypeNode; |
-import com.google.dart.compiler.ast.DartTypeParameter; |
-import com.google.dart.compiler.ast.DartUnaryExpression; |
-import com.google.dart.compiler.ast.DartUnit; |
-import com.google.dart.compiler.ast.DartUnqualifiedInvocation; |
-import com.google.dart.compiler.ast.DartVariable; |
-import com.google.dart.compiler.ast.DartVariableStatement; |
-import com.google.dart.compiler.ast.DartWhileStatement; |
-import com.google.dart.compiler.ast.Modifiers; |
-import com.google.dart.compiler.parser.Token; |
-import com.google.dart.compiler.resolver.ClassElement; |
-import com.google.dart.compiler.resolver.CoreTypeProvider; |
-import com.google.dart.compiler.resolver.Element; |
-import com.google.dart.compiler.resolver.ElementKind; |
-import com.google.dart.compiler.resolver.FieldElement; |
-import com.google.dart.compiler.resolver.MethodElement; |
-import com.google.dart.compiler.resolver.VariableElement; |
-import com.google.dart.compiler.type.FunctionType; |
-import com.google.dart.compiler.type.InterfaceType; |
-import com.google.dart.compiler.type.InterfaceType.Member; |
-import com.google.dart.compiler.type.Type; |
-import com.google.dart.compiler.type.TypeKind; |
-import com.google.dart.compiler.type.Types; |
- |
-import java.util.HashMap; |
-import java.util.HashSet; |
-import java.util.List; |
-import java.util.Map; |
-import java.util.Set; |
- |
-public class TypeHeuristicImplementation implements TypeHeuristic { |
- |
- private ExpressionTypeInfo typeInfo; |
- private final Set<Type> dynTypes; |
- |
- public TypeHeuristicImplementation(DartUnit unit, CoreTypeProvider typeProvider) { |
- typeInfo = TypeInfoVisitor.computeTypeInfo(unit, typeProvider); |
- dynTypes = Sets.<Type> newHashSet(typeProvider.getDynamicType()); |
- } |
- |
- @Override |
- public Set<Type> getTypesOf(DartExpression expr) { |
- Set<Type> types = typeInfo.getTypeSets().get(expr.getNormalizedNode()); |
- if (types != null) { |
- return types; |
- } |
- return dynTypes; |
- } |
- |
- @Override |
- public boolean isDynamic(Set<Type> types) { |
- return (types == dynTypes || (types.size() > 1) || TypeKind.of(types.iterator().next()) |
- .equals(TypeKind.DYNAMIC)); |
- } |
- |
- @Override |
- public Set<MethodElement> getImplementationsOf(DartExpression expr) { |
- return typeInfo.getMethodImpl().get(expr.getNormalizedNode()); |
- } |
- |
- @Override |
- public Set<FieldElement> getFieldImplementationsOf(DartExpression expr, FieldKind fieldKind) { |
- Set<FieldElement> fields = null; |
- if (fieldKind == FieldKind.GETTER) { |
- fields = typeInfo.getGettersImpl().get(expr.getNormalizedNode()); |
- } else { |
- fields = typeInfo.getSettersImpl().get(expr.getNormalizedNode()); |
- } |
- assert assertFieldsMatch(fields, fieldKind); |
- return fields; |
- } |
- |
- public static Element maybeGetTargetElement(DartExpression expr) { |
- return maybeGetTargetElement(expr, null); |
- } |
- |
- private static Element maybeGetTargetElement(DartNode dartNode, Set<Element> elements) { |
- Element element = null; |
- String propName = null; |
- elements = Sets.newHashSet(); |
- if (dartNode instanceof DartPropertyAccess) { |
- DartPropertyAccess propAccess = (DartPropertyAccess) dartNode; |
- propName = propAccess.getPropertyName(); |
- element = maybeGetTargetElement(propAccess.getQualifier(), elements); |
- } else if (dartNode instanceof DartIdentifier) { |
- element = ((DartIdentifier) dartNode).getTargetSymbol(); |
- if (ElementKind.of(element).equals(ElementKind.FIELD)) { |
- propName = element.getName(); |
- element = element.getEnclosingElement(); |
- } else { |
- return element; |
- } |
- } else if (dartNode instanceof DartArrayAccess) { |
- return maybeGetTargetElement(((DartArrayAccess) dartNode).getTarget()); |
- } |
- if (element != null) { |
- if (TypeKind.of(element.getType()).equals(TypeKind.INTERFACE)) { |
- InterfaceType iType = (InterfaceType) element.getType(); |
- Member member = iType.lookupMember(propName); |
- if (member != null) { |
- element = member.getElement(); |
- elements.add(element); |
- } |
- ClassElement classElement = iType.getElement(); |
- for (InterfaceType subType : classElement.getSubtypes()) { |
- member = subType.lookupMember(propName); |
- if (member != null) { |
- elements.add(member.getElement()); |
- } |
- } |
- if (elements.size() != 1) { |
- return null; |
- } |
- } else { |
- // TypeKind (DYNAMIC, NONE, FUNCTION, ...) |
- return null; |
- } |
- } |
- return element; |
- } |
- |
- private static boolean assertFieldsMatch(Set<FieldElement> fields, FieldKind fieldKind) { |
- if (fields == null) { |
- return true; |
- } |
- boolean allMatch = true; |
- for (FieldElement fieldElement : fields) { |
- boolean singleMatch; |
- Modifiers modifiers = fieldElement.getModifiers(); |
- if (modifiers.isAbstractField()) { |
- singleMatch = fieldKind == FieldKind.GETTER ? fieldElement.getGetter() != null |
- : fieldElement.getSetter() != null; |
- } else { |
- singleMatch = true; |
- } |
- allMatch &= singleMatch; |
- } |
- return allMatch; |
- } |
- |
- private static class TypeInfoVisitor implements DartPlainVisitor<Type> { |
- |
- private final ExpressionTypeInfo typeInfo; |
- private final CoreTypeProvider typeProvider; |
- private final Types typeUtils; |
- private InterfaceType currentClass; |
- Set<Element> visitedConstants; |
- |
- public static ExpressionTypeInfo computeTypeInfo(DartUnit unit, CoreTypeProvider typeProvider) { |
- TypeInfoVisitor typeInfoVisitor = new TypeInfoVisitor(typeProvider); |
- typeInfoVisitor.visitUnit(unit); |
- return typeInfoVisitor.typeInfo; |
- } |
- |
- private TypeInfoVisitor(CoreTypeProvider typeProvider) { |
- this.typeProvider = typeProvider; |
- this.typeUtils = Types.getInstance(typeProvider); |
- this.typeInfo = ExpressionTypeInfo.create(); |
- } |
- |
- @Override |
- public Type visitUnit(DartUnit node) { |
- visitedConstants = Sets.newHashSet(); |
- Type type = visitChildrenAndReturnVoid(node); |
- visitedConstants = null; |
- return type; |
- } |
- |
- @Override |
- public Type visitClass(DartClass node) { |
- beginClassContext(node); |
- visitChildren(node); |
- endClassContext(); |
- return dynamicType(); |
- } |
- |
- private void beginClassContext(DartClass node) { |
- currentClass = node.getSymbol().getType(); |
- } |
- |
- private void endClassContext() { |
- currentClass = null; |
- } |
- |
- @Override |
- public Type visitThisExpression(DartThisExpression node) { |
- return recordTypeInfo(node, currentClass.getElement().getType()); |
- } |
- |
- @Override |
- public Type visitArrayLiteral(DartArrayLiteral node) { |
- visit(node.getExpressions()); |
- return getType(node); |
- } |
- |
- @Override |
- public Type visitMapLiteral(DartMapLiteral node) { |
- return recordTypeInfo(node, getType(node)); |
- } |
- |
- @Override |
- public Type visitMapLiteralEntry(DartMapLiteralEntry node) { |
- return computeType(node); |
- } |
- |
- @Override |
- public Type visitBooleanLiteral(DartBooleanLiteral node) { |
- return recordTypeInfo(node, getType(node)); |
- } |
- |
- @Override |
- public Type visitDoubleLiteral(DartDoubleLiteral node) { |
- return recordTypeInfo(node, getType(node)); |
- } |
- |
- @Override |
- public Type visitIntegerLiteral(DartIntegerLiteral node) { |
- return recordTypeInfo(node, getType(node)); |
- } |
- |
- @Override |
- public Type visitStringLiteral(DartStringLiteral node) { |
- return recordTypeInfo(node, getType(node)); |
- } |
- |
- @Override |
- public Type visitStringInterpolation(DartStringInterpolation node) { |
- return recordTypeInfo(node, getType(node)); |
- } |
- |
- @Override |
- public Type visitNullLiteral(DartNullLiteral node) { |
- return recordTypeInfo(node, nullType()); |
- } |
- |
- @Override |
- public Type visitParenthesizedExpression(DartParenthesizedExpression node) { |
- return recordTypeInfo(node, computeType(node.getExpression())); |
- } |
- |
- @Override |
- public Type visitTypeNode(DartTypeNode node) { |
- return node.getType() == null ? dynamicType() : node.getType(); |
- } |
- |
- @Override |
- public Type visitBlock(DartBlock node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitBreakStatement(DartBreakStatement node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitContinueStatement(DartContinueStatement node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitDefault(DartDefault node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitEmptyStatement(DartEmptyStatement node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitExprStmt(DartExprStmt node) { |
- return visit(node.getExpression()); |
- } |
- |
- @Override |
- public Type visitParameter(DartParameter node) { |
- visit(node.getDefaultExpr()); |
- return getType(node); |
- } |
- |
- @Override |
- public Type visitMethodDefinition(DartMethodDefinition node) { |
- visitChildren(node); |
- return getType(node); |
- } |
- |
- @Override |
- public Type visitNewExpression(DartNewExpression node) { |
- visit(node.getArgs()); |
- return getType(node); |
- } |
- |
- @Override |
- public Type visitMethodInvocation(DartMethodInvocation node) { |
- visit(node.getArgs()); |
- Type type = computeType(node.getTarget()); |
- String selectorName = node.getFunctionNameString(); |
- type = computeAndRecordSelectorTypes(node, type, selectorName); |
- return type; |
- } |
- |
- @Override |
- public Type visitFunction(DartFunction node) { |
- visit(node.getParams()); |
- computeType(node.getBody()); |
- return getType(node.getReturnTypeNode()); |
- } |
- |
- @Override |
- public Type visitAssertion(DartAssertion node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitImportDirective(DartImportDirective node) { |
- return voidType(); |
- } |
- |
- @Override |
- public Type visitLibraryDirective(DartLibraryDirective node) { |
- return voidType(); |
- } |
- |
- @Override |
- public Type visitNativeDirective(DartNativeDirective node) { |
- return voidType(); |
- } |
- |
- @Override |
- public Type visitResourceDirective(DartResourceDirective node) { |
- return voidType(); |
- } |
- |
- @Override |
- public Type visitSourceDirective(DartSourceDirective node) { |
- return voidType(); |
- } |
- |
- @Override |
- public void visit(List<? extends DartNode> nodes) { |
- if (nodes != null) { |
- for (DartNode node : nodes) { |
- node.getNormalizedNode().accept(this); |
- } |
- } |
- } |
- |
- @Override |
- public Type visitArrayAccess(DartArrayAccess node) { |
- Type type = computeType(node.getTarget()); |
- type = computeAndRecordSelectorTypes(node, type, getOperatorSelectorName(Token.INDEX)); |
- visit(node.getKey()); |
- return type; |
- } |
- |
- @Override |
- public Type visitPropertyAccess(DartPropertyAccess node) { |
- String selectorName = node.getPropertyName(); |
- Type receiver = computeType(node.getQualifier()); |
- Type selectorType = computeAndRecordSelectorTypes(node, receiver, selectorName); |
- return selectorType; |
- } |
- |
- private boolean canBindConstantValue(DartExpression expr) { |
- if (expr instanceof DartLiteral) { |
- return true; |
- } else if (expr instanceof DartBinaryExpression) { |
- DartBinaryExpression binExpr = (DartBinaryExpression) expr; |
- return canBindConstantValue(binExpr.getArg1()) && canBindConstantValue(binExpr.getArg2()); |
- } else if (expr instanceof DartUnaryExpression) { |
- return canBindConstantValue(((DartUnaryExpression) expr).getArg()); |
- } else if (expr instanceof DartParenthesizedExpression) { |
- return canBindConstantValue(((DartParenthesizedExpression) expr).getExpression()); |
- } else if (expr instanceof DartIdentifier || expr instanceof DartPropertyAccess) { |
- Element e = maybeGetTargetElement(expr); |
- switch (ElementKind.of(e)) { |
- case FIELD: |
- if (visitedConstants.contains(e)) { |
- return false; |
- } |
- visitedConstants.add(e); |
- FieldElement field = (FieldElement) e; |
- DartField fieldNode = (DartField) field.getNode(); |
- boolean result = field.getModifiers().isFinal() |
- && canBindConstantValue(fieldNode.getValue()); |
- visitedConstants.remove(e); |
- return result; |
- case VARIABLE: |
- VariableElement var = (VariableElement) e; |
- DartVariable varNode = (DartVariable) var.getNode(); |
- return var.getModifiers().isFinal() && canBindConstantValue(varNode.getValue()); |
- } |
- } |
- return false; |
- } |
- |
- private void maybeBindConstantValues(DartExpression expr, boolean isAssignee) { |
- if (canBindConstantValue(expr) && (expr == expr.getNormalizedNode())) { |
- DartExpression foldedExpr = null; |
- Element target = maybeGetTargetElement(expr); |
- switch (ElementKind.of(target)) { |
- case VARIABLE: |
- if (!isAssignee && target.getModifiers().isFinal()) { |
- DartVariable var = (DartVariable) target.getNode(); |
- foldedExpr = (DartExpression) var.getValue().clone(); |
- } |
- break; |
- case FIELD: |
- if (target.getModifiers().isFinal()) { |
- DartField field = (DartField) target.getNode(); |
- foldedExpr = (DartExpression) field.getValue().clone(); |
- } |
- break; |
- default: |
- return; |
- } |
- // TODO (fabiomfv) : consider adding normalized field to DartExpression. |
- if (foldedExpr != null) { |
- if (expr instanceof DartIdentifier) { |
- ((DartIdentifier) expr).setNormalizedNode(foldedExpr); |
- } else if (expr instanceof DartPropertyAccess) { |
- ((DartPropertyAccess) expr).setNormalizedNode(foldedExpr); |
- } |
- } |
- } |
- } |
- |
- @Override |
- public Type visitBinaryExpression(DartBinaryExpression node) { |
- Token opToken = node.getOperator(); |
- maybeBindConstantValues(node.getArg1(), opToken.isAssignmentOperator()); |
- Type receiver = computeType(node.getArg1()); |
- maybeBindConstantValues(node.getArg2(), false); |
- computeType(node.getArg2()); |
- switch (opToken) { |
- case ADD: |
- case SUB: |
- case MUL: |
- case DIV: |
- case MOD: |
- case BIT_AND: |
- case BIT_OR: |
- case BIT_XOR: |
- case SAR: |
- case SHL: |
- case ASSIGN_ADD: |
- case ASSIGN_SUB: |
- case ASSIGN_MUL: |
- case ASSIGN_DIV: |
- case ASSIGN_MOD: |
- case ASSIGN_BIT_AND: |
- case ASSIGN_BIT_OR: |
- case ASSIGN_BIT_XOR: |
- case ASSIGN_SAR: |
- case ASSIGN_SHL: { |
- computeAndRecordSelectorTypes(node, receiver, getOperatorSelectorName(opToken)); |
- return receiver; |
- } |
- |
- case NE: |
- // There is no NE operator implementation. NE is conceptually implemented as !(e1 == e2). |
- assert !opToken.isUserDefinableOperator() : "Transformation at the line below is not valid anymore"; |
- opToken = Token.EQ; |
- // $FALL-THROUGH$ |
- case AND: |
- case OR: |
- case NOT: |
- case EQ: |
- case EQ_STRICT: |
- case NE_STRICT: |
- case LT: |
- case GT: |
- case LTE: |
- case GTE: { |
- Type opType = boolType(); |
- computeAndRecordSelectorTypes(node, receiver, getOperatorSelectorName(opToken)); |
- recordTypeInfo(node, Sets.newHashSet(opType)); |
- return opType; |
- } |
- |
- case ASSIGN: { |
- return receiver; |
- } |
- |
- case COMMA: |
- return computeType(node.getArg2()); |
- } |
- return dynamicType(); |
- } |
- |
- // Object is implicit and when looking for == operator we will never find Object== if a child |
- // class overrides it. Since Object is also an exception when calling classElement.getSubTypes() |
- // we need to handle this as a special case. |
- private void maybeAddObjectSelectors(DartExpression node, Type receiver, String selectorName) { |
- Member iMember = typeProvider.getObjectType().lookupMember(selectorName); |
- if ((iMember != null) && ElementKind.of(iMember.getElement()).equals(ElementKind.METHOD)) { |
- recordMethodImpl(node, (MethodElement) iMember.getElement()); |
- } |
- } |
- |
- private Type computeAndRecordSelectorTypes(DartExpression expression, Type receiver, |
- String selectorName) { |
- Type type = dynamicType(); |
- if (receiver != null) { |
- if (TypeKind.of(receiver).equals(TypeKind.INTERFACE)) { |
- InterfaceType baseType = (InterfaceType) receiver; |
- Set<Type> types = Sets.newHashSet(); |
- for (InterfaceType subType : baseType.getElement().getSubtypes()) { |
- InterfaceType sType = subType; |
- if (isParameterizedType(sType)) { |
- sType = substSubType(sType, baseType); |
- } |
- Type computedType = computeAndRecordSelectorType(expression, sType, selectorName); |
- // void is returned as dynamic. return null to make sure void is not a valid expression |
- // return type as in setters or void methods. |
- if (computedType != null) { |
- type = computedType; |
- types.addAll(getConcreteSubTypes(type)); |
- } |
- } |
- if (types.size() > 1) { |
- type = getCommonSuperType(types); |
- types = Sets.newHashSet(dynamicType()); |
- } |
- recordTypeInfo(expression, types); |
- } |
- } |
- return type; |
- } |
- |
- private Type computeAndRecordSelectorType(DartExpression expression, InterfaceType type, |
- String selectorName) { |
- Member iMember = type.lookupMember(selectorName); |
- // TODO (fabiomfv): refactor this. |
- if (iMember != null) { |
- Element element = iMember.getElement(); |
- switch (ElementKind.of(element)) { |
- case METHOD: |
- if (!type.getElement().isInterface()) { |
- recordMethodImpl(expression, (MethodElement) element); |
- maybeAddObjectSelectors(expression, type, selectorName); |
- } |
- if (canInstantiateParametrizedType(iMember)) { |
- FunctionType ftype = (FunctionType) iMember.getType(); |
- return ftype.getReturnType(); |
- } |
- return dynamicType(); |
- case FIELD: |
- FieldElement fieldElement = (FieldElement) element; |
- recordFieldImpl(expression, fieldElement); |
- Modifiers modifiers = fieldElement.getModifiers(); |
- if (modifiers.isAbstractField() && modifiers.isSetter()) { |
- // void is currently dynamic which make the computation incorrect. |
- return null; |
- } |
- return iMember.getType(); |
- default: |
- } |
- } |
- return dynamicType(); |
- } |
- |
- private Set<Type> getConcreteSubTypes(Type type) { |
- Set<Type> concreteTypes = Sets.<Type> newHashSet(); |
- if (TypeKind.of(type).equals(TypeKind.INTERFACE)) { |
- ClassElement cls = (ClassElement) type.getElement(); |
- for (InterfaceType subType : cls.getSubtypes()) { |
- if (!subType.getElement().isInterface()) { |
- concreteTypes.add(substSubType(subType, (InterfaceType) type)); |
- } |
- } |
- } |
- return concreteTypes; |
- } |
- |
- private InterfaceType substSubType(InterfaceType subType, InterfaceType baseType) { |
- List<Type> typeArgs = baseType.getArguments(); |
- List<Type> typeParams = asInstanceOf(subType, baseType.getElement()).getArguments(); |
- if (typeArgs != null && !typeArgs.isEmpty()) { |
- return subType.subst(typeArgs, typeParams); |
- } |
- return subType; |
- } |
- |
- private boolean isParameterizedType(InterfaceType type) { |
- return type.getArguments() != null && !type.getArguments().isEmpty(); |
- } |
- |
- private boolean canInstantiateParametrizedType(Member member) { |
- InterfaceType iface = member.getHolder(); |
- List<Type> typeArgs = iface.getArguments(); |
- List<Type> typeParams = iface.getElement().getTypeParameters(); |
- return typeArgs.size() == typeParams.size(); |
- } |
- |
- @Override |
- public Type visitIdentifier(DartIdentifier node) { |
- Element element = node.getTargetSymbol(); |
- switch (ElementKind.of(element)) { |
- case CLASS: |
- recordTypeInfo(node, element.getType()); |
- return element.getType(); |
- case VARIABLE: |
- case PARAMETER: |
- Type type = element.getType(); |
- recordTypeInfo(node, Sets.<Type> newHashSet(type)); |
- return type; |
- case FIELD: { |
- Element enclosing = element.getEnclosingElement(); |
- switch (ElementKind.of(enclosing)) { |
- case CLASS: |
- ClassElement cls = (ClassElement) enclosing; |
- computeAndRecordSelectorTypes(node, cls.getType(), element.getName()); |
- break; |
- case LIBRARY: |
- // TODO (fabiomfv). |
- } |
- return element.getType(); |
- } |
- default: |
- return dynamicType(); |
- } |
- } |
- |
- @Override |
- public Type visitUnaryExpression(DartUnaryExpression node) { |
- maybeBindConstantValues(node.getArg(), true); |
- Type receiver = computeType(node.getArg()); |
- Token op = node.getOperator(); |
- switch (node.getOperator()) { |
- case NOT: |
- assert !op.isUserDefinableOperator(); |
- receiver = boolType(); |
- break; |
- case INC: |
- case DEC: |
- assert !op.isUserDefinableOperator(); |
- receiver = intType(); |
- break; |
- case SUB: |
- case BIT_NOT: |
- computeAndRecordSelectorTypes(node, receiver, getOperatorSelectorName(op)); |
- break; |
- } |
- recordTypeInfo(node, receiver); |
- return receiver; |
- } |
- |
- @Override |
- public Type visitUnqualifiedInvocation(DartUnqualifiedInvocation node) { |
- visit(node.getArgs()); |
- Type type = getType(node); |
- if (node.getTarget() != null) { |
- String selectorName = node.getTarget().getTargetName(); |
- Element element = node.getTarget().getTargetSymbol(); |
- if (element == null) { |
- return type; |
- } |
- Element enclosing = element.getEnclosingElement(); |
- switch (ElementKind.of(enclosing)) { |
- case CLASS: { |
- ClassElement cls = (ClassElement) element.getEnclosingElement(); |
- switch (ElementKind.of(element)) { |
- case FIELD: |
- computeAndRecordSelectorTypes(node, cls.getType(), selectorName); |
- type = element.getType(); |
- break; |
- case METHOD: |
- computeAndRecordSelectorTypes(node, cls.getType(), selectorName); |
- FunctionType fType = (FunctionType) element.getType(); |
- type = fType.getReturnType(); |
- break; |
- default: |
- type = element.getType(); |
- break; |
- } |
- break; |
- } |
- case LIBRARY: |
- // TODO (fabiomfv). |
- break; |
- case NONE: |
- if (TypeKind.of(element.getType()).equals(TypeKind.FUNCTION)) { |
- type = ((FunctionType) element.getType()).getReturnType(); |
- recordTypeInfo(node, type); |
- } |
- break; |
- } |
- } |
- return type; |
- } |
- |
- @Override |
- public Type visitField(DartField node) { |
- visitChildren(node); |
- return getType(node); |
- } |
- |
- @Override |
- public Type visitFieldDefinition(DartFieldDefinition node) { |
- visitChildrenAndReturnVoid(node); |
- Type type = getType(node); |
- return type; |
- } |
- |
- @Override |
- public Type visitFunctionExpression(DartFunctionExpression node) { |
- visitChildren(node); |
- return dynamicType(); |
- } |
- |
- @Override |
- public Type visitFunctionTypeAlias(DartFunctionTypeAlias node) { |
- return dynamicType(); |
- } |
- |
- @Override |
- public Type visitFunctionObjectInvocation(DartFunctionObjectInvocation node) { |
- visit(node.getArgs()); |
- Type type = computeType(node.getTarget()); |
- recordTypeInfo(node, type); |
- return type; |
- } |
- |
- @Override |
- public Type visitCase(DartCase node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitConditional(DartConditional node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitDoWhileStatement(DartDoWhileStatement node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitForInStatement(DartForInStatement node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitForStatement(DartForStatement node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitIfStatement(DartIfStatement node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitInitializer(DartInitializer node) { |
- visit(node.getValue()); |
- return voidType(); |
- } |
- |
- @Override |
- public Type visitLabel(DartLabel node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitReturnStatement(DartReturnStatement node) { |
- return (node.getValue() == null) ? voidType() : computeType(node.getValue()); |
- } |
- |
- @Override |
- public Type visitSuperExpression(DartSuperExpression node) { |
- visitChildren(node); |
- return getType(node); |
- } |
- |
- @Override |
- public Type visitSwitchStatement(DartSwitchStatement node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitSyntheticErrorExpression(DartSyntheticErrorExpression node) { |
- visitChildren(node); |
- return dynamicType(); |
- } |
- |
- @Override |
- public Type visitSyntheticErrorStatement(DartSyntheticErrorStatement node) { |
- visitChildren(node); |
- return dynamicType(); |
- } |
- |
- @Override |
- public Type visitThrowStatement(DartThrowStatement node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitCatchBlock(DartCatchBlock node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitTryStatement(DartTryStatement node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitVariable(DartVariable node) { |
- maybeBindConstantValues(node.getValue(), false); |
- visit(node.getValue()); |
- return dynamicType(); |
- } |
- |
- @Override |
- public Type visitVariableStatement(DartVariableStatement node) { |
- Type type = computeType(node.getTypeNode()); |
- visitChildren(node); |
- return type; |
- } |
- |
- @Override |
- public Type visitWhileStatement(DartWhileStatement node) { |
- return visitChildrenAndReturnVoid(node); |
- } |
- |
- @Override |
- public Type visitNamedExpression(DartNamedExpression node) { |
- visit(node.getExpression()); |
- return getType(node.getExpression()); |
- } |
- |
- @Override |
- public Type visitTypeExpression(DartTypeExpression node) { |
- return getType(node); |
- } |
- |
- @Override |
- public Type visitTypeParameter(DartTypeParameter node) { |
- return getType(node); |
- } |
- |
- @Override |
- public Type visitNativeBlock(DartNativeBlock node) { |
- return dynamicType(); |
- } |
- |
- @Override |
- public Type visitRedirectConstructorInvocation(DartRedirectConstructorInvocation node) { |
- return getType(node); |
- } |
- |
- @Override |
- public Type visitSuperConstructorInvocation(DartSuperConstructorInvocation node) { |
- return getType(node); |
- } |
- |
- @Override |
- public Type visitParameterizedTypeNode(DartParameterizedTypeNode node) { |
- return node.getExpression().accept(this); |
- } |
- |
- private Type recordTypeInfo(DartExpression node, Type type) { |
- if (type == null) { |
- return type; |
- } |
- DartExpression targetNode = node.getNormalizedNode(); |
- Map<DartExpression, Set<Type>> typeSets = typeInfo.getTypeSets(); |
- Set<Type> types = typeSets.get(targetNode); |
- if (types == null) { |
- types = new HashSet<Type>(); |
- } |
- switch (TypeKind.of(type)) { |
- case INTERFACE: { |
- ClassElement cls = (ClassElement) type.getElement(); |
- for (InterfaceType subType : cls.getSubtypes()) { |
- InterfaceType rSubType = substSubType(subType, (InterfaceType) type); |
- if (!rSubType.getElement().isInterface()) { |
- types.add(rSubType); |
- } |
- } |
- } |
- break; |
- case FUNCTION: |
- case FUNCTION_ALIAS: |
- case VARIABLE: |
- // We dont handle these yet. |
- case DYNAMIC: |
- case NONE: |
- types.add(dynamicType()); |
- break; |
- } |
- // We need to be resilient. in case interface is defined with no concrete |
- // types, we should |
- // not add any partial/incomplete type info we may have gathered so far. |
- // for instance DOM does not have concrete types yet. |
- if (!types.isEmpty()) { |
- typeSets.put(targetNode, types); |
- } |
- return type; |
- } |
- |
- private void recordMethodImpl(DartExpression expression, MethodElement method) { |
- assert method != null; |
- Set<MethodElement> methodImpls = typeInfo.getMethodImpl().get(expression); |
- if (methodImpls == null) { |
- methodImpls = Sets.newHashSet(); |
- typeInfo.getMethodImpl().put(expression, methodImpls); |
- } |
- methodImpls.add(method); |
- } |
- |
- private void recordFieldImpl(DartExpression expression, FieldElement field) { |
- assert field != null; |
- Set<FieldElement> getters = typeInfo.getGettersImpl().get(expression); |
- if (getters == null) { |
- getters = Sets.newHashSet(); |
- typeInfo.getGettersImpl().put(expression, getters); |
- } |
- Set<FieldElement> setters = typeInfo.getSettersImpl().get(expression); |
- if (setters == null) { |
- setters = Sets.newHashSet(); |
- typeInfo.getSettersImpl().put(expression, setters); |
- } |
- Modifiers modifiers = field.getModifiers(); |
- if (modifiers.isAbstractField()) { |
- if (field.getSetter() != null) { |
- setters.add(field); |
- } |
- if (field.getGetter() != null) { |
- getters.add(field); |
- } |
- } else { |
- getters.add(field); |
- setters.add(field); |
- } |
- } |
- |
- private void recordTypeInfo(DartExpression node, Set<Type> types) { |
- for (Type type : types) { |
- recordTypeInfo(node, type); |
- } |
- } |
- |
- void visitChildren(DartNode node) { |
- node.getNormalizedNode().visitChildren(this); |
- } |
- |
- private Type visitChildrenAndReturnVoid(DartNode node) { |
- visitChildren(node); |
- return voidType(); |
- } |
- |
- private Type visit(DartExpression expression) { |
- if (expression != null) { |
- return expression.getNormalizedNode().accept(this); |
- } |
- return voidType(); |
- } |
- |
- Type getType(DartNode node) { |
- return (node == null) ? dynamicType() : node.getNormalizedNode().getType(); |
- } |
- |
- Type computeType(DartNode node) { |
- return (node == null) ? dynamicType() : node.getNormalizedNode().accept(this); |
- } |
- |
- private Type dynamicType() { |
- return typeProvider.getDynamicType(); |
- } |
- |
- private Type nullType() { |
- return typeProvider.getNullType(); |
- } |
- |
- private Type boolType() { |
- return typeProvider.getBoolType(); |
- } |
- |
- private Type intType() { |
- return typeProvider.getIntType(); |
- } |
- |
- private Type voidType() { |
- return typeProvider.getVoidType(); |
- } |
- |
- private String getOperatorSelectorName(Token op) { |
- switch (op) { |
- case SUB: |
- return "operator negate"; |
- |
- case ASSIGN_ADD: |
- return getOperatorSelectorName(Token.ADD); |
- case ASSIGN_SUB: |
- return getOperatorSelectorName(Token.SUB); |
- case ASSIGN_MUL: |
- return getOperatorSelectorName(Token.MUL); |
- case ASSIGN_DIV: |
- return getOperatorSelectorName(Token.DIV); |
- |
- case ASSIGN_BIT_OR: |
- return getOperatorSelectorName(Token.BIT_OR); |
- case ASSIGN_BIT_XOR: |
- return getOperatorSelectorName(Token.BIT_XOR); |
- case ASSIGN_BIT_AND: |
- return getOperatorSelectorName(Token.BIT_AND); |
- |
- case ASSIGN_SHL: |
- return getOperatorSelectorName(Token.SHL); |
- case ASSIGN_SAR: |
- return getOperatorSelectorName(Token.SAR); |
- } |
- return ("operator " + op.getSyntax()); |
- } |
- |
- private InterfaceType asInstanceOf(Type t, ClassElement element) { |
- return typeUtils.asInstanceOf(t, element); |
- } |
- |
- // TODO (fabiomfv) : revisit this. |
- // returns the 'root' type of the set of types or dynamic if can't find a common root type. |
- private Type getCommonSuperType(Set<Type> ts) { |
- if (ts.size() == 1) { |
- return ts.iterator().next(); |
- } |
- for (Type t : ts) { |
- if (TypeKind.of(t).equals(TypeKind.INTERFACE) && isSuperTypeOf(t, ts)) { |
- if (((ClassElement) t.getElement()).isObject()) { |
- continue; |
- } |
- return t; |
- } |
- } |
- return dynamicType(); |
- } |
- |
- private boolean isSuperTypeOf(Type type, Set<Type> sts) { |
- for (Type st : sts) { |
- st.getClass(); |
- type.getClass(); |
- if (!typeUtils.isSubtype(st, type)) { |
- return false; |
- } |
- } |
- return true; |
- } |
- } |
- |
- /** |
- * Stores expressions type and implementation information. |
- */ |
- static class ExpressionTypeInfo { |
- |
- private final Map<DartExpression, Set<Type>> typeSets; |
- private final Map<DartExpression, Set<FieldElement>> getterImpl; |
- private final Map<DartExpression, Set<FieldElement>> setterImpl; |
- private final Map<DartExpression, Set<MethodElement>> methodImpl; |
- |
- static ExpressionTypeInfo create() { |
- return new ExpressionTypeInfo(); |
- } |
- |
- private ExpressionTypeInfo() { |
- this.typeSets = new HashMap<DartExpression, Set<Type>>(); |
- this.getterImpl = new HashMap<DartExpression, Set<FieldElement>>(); |
- this.setterImpl = new HashMap<DartExpression, Set<FieldElement>>(); |
- this.methodImpl = new HashMap<DartExpression, Set<MethodElement>>(); |
- } |
- |
- Map<DartExpression, Set<Type>> getTypeSets() { |
- return typeSets; |
- } |
- |
- Map<DartExpression, Set<FieldElement>> getGettersImpl() { |
- return getterImpl; |
- } |
- |
- Map<DartExpression, Set<FieldElement>> getSettersImpl() { |
- return setterImpl; |
- } |
- |
- Map<DartExpression, Set<MethodElement>> getMethodImpl() { |
- return methodImpl; |
- } |
- } |
-} |