Chromium Code Reviews| Index: lib/compiler/implementation/ssa/builder.dart |
| diff --git a/lib/compiler/implementation/ssa/builder.dart b/lib/compiler/implementation/ssa/builder.dart |
| index 4f4afed3e79c44934fc8442b8dda423643c74f1a..1776b892d1875f33321f6cc7a908cd996827a7ba 100644 |
| --- a/lib/compiler/implementation/ssa/builder.dart |
| +++ b/lib/compiler/implementation/ssa/builder.dart |
| @@ -3138,8 +3138,13 @@ class SsaBuilder extends ResolvedVisitor implements Visitor { |
| } |
| bool tryBuildConstantSwitch(SwitchStatement node) { |
| + // TODO(lrn): Move the constant resolution to the resolver, so |
| + // we can report an error before reaching the backend. |
| Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>(); |
| - // First check whether all case expressions are compile-time constants. |
| + // First check whether all case expressions are compile-time constants, |
| + // and all have the same type that doesn't override operator==. |
| + Constant firstConstant = null; |
| + bool failure = false; |
| for (SwitchCase switchCase in node.cases) { |
| for (Node labelOrCase in switchCase.labelsAndCases) { |
| if (labelOrCase is CaseMatch) { |
| @@ -3147,14 +3152,37 @@ class SsaBuilder extends ResolvedVisitor implements Visitor { |
| Constant constant = |
| compiler.constantHandler.tryCompileNodeWithDefinitions( |
| match.expression, elements); |
| - if (constant === null) return false; |
| + if (constant === null) { |
| + compiler.reportWarning(match.expression, |
| + MessageKind.NOT_A_COMPILE_TIME_CONSTANT.error()); |
| + failure = true; |
| + continue; |
| + } |
| + if (firstConstant == null) { |
| + firstConstant = constant; |
| + if (nonPrimitiveTypeOverridesEquals(constant)) { |
| + compiler.reportWarning(match.expression, |
| + MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS.error()); |
| + failure = true; |
| + } |
| + } else { |
| + if (!constant.isSameType(firstConstant)) { |
| + compiler.reportWarning(match.expression, |
| + MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL.error()); |
| + failure = true; |
| + } |
| + } |
| constants[labelOrCase] = constant; |
| } else { |
| - // We don't handle labels yet. |
| - return false; |
| + compiler.reportWarning(node, "Unsupported: Labels on cases"); |
| + failure = true; |
| } |
| } |
| } |
| + if (failure) { |
| + return false; |
| + } |
| + |
| // TODO(ngeoffray): Handle switch-instruction in bailout code. |
| work.allowSpeculativeOptimization = false; |
| // Then build a switch structure. |
| @@ -3266,6 +3294,29 @@ class SsaBuilder extends ResolvedVisitor implements Visitor { |
| return true; |
| } |
| + bool nonPrimitiveTypeOverridesEquals(Constant constant) { |
| + // If constant is primitive, just return false. We know |
| + // about the equals methods of num/String classes. |
| + // [Map] and [List] does not override equals. |
|
floitsch
2012/08/30 14:08:18
do not
Lasse Reichstein Nielsen
2012/09/03 09:12:56
Done.
|
| + if (!constant.isConstructedObject()) return false; |
| + |
| + ConstructedConstant constructedConstant = constant; |
| + Type type = constructedConstant.type; |
| + assert(type !== null); |
| + Element element = type.element; |
|
ngeoffray
2012/08/30 07:29:13
The code below probably deserves to be in a helper
Lasse Reichstein Nielsen
2012/08/30 10:54:25
Any wish for the abstraction level?
isOverridingEq
ngeoffray
2012/08/30 11:07:13
I like the three of them :) The first two are easy
Lasse Reichstein Nielsen
2012/09/03 09:12:56
I went with
typeOverridesObjectEquals
and
lookup
|
| + // If the type is not a class, we'll just assume it overrides |
| + // operator==. Typedefs do, since [Function] does. |
| + if (!element.isClass()) return true; |
| + ClassElement classElement = element; |
| + SourceString dartMethodName = Elements.constructOperatorName( |
| + const SourceString('operator'), |
| + const SourceString('==')); |
| + Element operatorEq = classElement.lookupMember(dartMethodName); |
| + if (operatorEq == null) return false; |
| + // If the operator== declaration is in Object, it's not overridden. |
| + return (operatorEq.getEnclosingClass() != compiler.objectClass); |
| + } |
| + |
| // Recursively build an if/else structure to match the cases. |
| void buildSwitchCases(Link<Node> cases, HInstruction expression, |
| @@ -3326,33 +3377,9 @@ class SsaBuilder extends ResolvedVisitor implements Visitor { |
| compiler.constantHandler.tryCompileNodeWithDefinitions( |
| match.expression, elements); |
| if (constant !== null) { |
| - if (constant.isInt()) { |
| - // Report the first mixed-string/int type error only. |
| - if (encounteredCaseTypes == STRING_TYPE) { |
| - compiler.reportWarning( |
| - match, MessageKind.INVALID_CASE_EXPRESSION_TYPE); |
| - } |
| - encounteredCaseTypes = combine(encounteredCaseTypes, INT_TYPE); |
| - } else if (constant.isString()) { |
| - if (encounteredCaseTypes == INT_TYPE) { |
| - compiler.reportWarning( |
| - match, MessageKind.INVALID_CASE_EXPRESSION_TYPE); |
| - } |
| - encounteredCaseTypes = combine(encounteredCaseTypes, STRING_TYPE); |
| - } else { |
| - compiler.reportWarning(match, |
| - MessageKind.INVALID_CASE_EXPRESSION); |
| - encounteredCaseTypes = CONFLICT_TYPE; |
| - } |
| stack.add(graph.addConstant(constant)); |
| } else { |
| - // TODO(lrn): Remove this else branch, and make the constant |
| - // evaluation mandatory when we are ready to break existing code using |
| - // non constant-int-or-string expressions. |
| - compiler.reportWarning(match, |
| - 'case expressions not compile-time constant int or string.'); |
| visit(match.expression); |
| - encounteredCaseTypes = CONFLICT_TYPE; |
| } |
| push(new HEquals(target, pop(), expression)); |
| } |