Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(161)

Side by Side Diff: lib/compiler/implementation/ssa/builder.dart

Issue 10916002: Change switch to give errors when cases don't follow the newest syntax. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: use .compileType on elements. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 class Interceptors { 5 class Interceptors {
6 Compiler compiler; 6 Compiler compiler;
7 Interceptors(Compiler this.compiler); 7 Interceptors(Compiler this.compiler);
8 8
9 SourceString mapOperatorToMethodName(Operator op) { 9 SourceString mapOperatorToMethodName(Operator op) {
10 String name = op.source.stringValue; 10 String name = op.source.stringValue;
(...skipping 3121 matching lines...) Expand 10 before | Expand all | Expand 10 after
3132 startBlock.setBlockFlow( 3132 startBlock.setBlockFlow(
3133 new HLabeledBlockInformation.implicit( 3133 new HLabeledBlockInformation.implicit(
3134 new HSubGraphBlockInformation(new SubGraph(startBlock, lastBlock)), 3134 new HSubGraphBlockInformation(new SubGraph(startBlock, lastBlock)),
3135 elements[node]), 3135 elements[node]),
3136 joinBlock); 3136 joinBlock);
3137 jumpHandler.close(); 3137 jumpHandler.close();
3138 } 3138 }
3139 3139
3140 bool tryBuildConstantSwitch(SwitchStatement node) { 3140 bool tryBuildConstantSwitch(SwitchStatement node) {
3141 Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>(); 3141 Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>();
3142 // First check whether all case expressions are compile-time constants. 3142 // First check whether all case expressions are compile-time constants,
3143 // and all have the same type that doesn't override operator==.
3144 // TODO(lrn): Move the constant resolution to the resolver, so
3145 // we can report an error before reaching the backend.
3146 DartType firstConstantType = null;
3147 bool failure = false;
3143 for (SwitchCase switchCase in node.cases) { 3148 for (SwitchCase switchCase in node.cases) {
3144 for (Node labelOrCase in switchCase.labelsAndCases) { 3149 for (Node labelOrCase in switchCase.labelsAndCases) {
3145 if (labelOrCase is CaseMatch) { 3150 if (labelOrCase is CaseMatch) {
3146 CaseMatch match = labelOrCase; 3151 CaseMatch match = labelOrCase;
3147 Constant constant = 3152 Constant constant =
3148 compiler.constantHandler.tryCompileNodeWithDefinitions( 3153 compiler.constantHandler.tryCompileNodeWithDefinitions(
3149 match.expression, elements); 3154 match.expression, elements);
3150 if (constant === null) return false; 3155 if (constant === null) {
3156 compiler.reportWarning(match.expression,
3157 MessageKind.NOT_A_COMPILE_TIME_CONSTANT.error());
3158 failure = true;
3159 continue;
3160 }
3161 if (firstConstantType == null) {
3162 firstConstantType = constant.computeType(compiler.constantHandler);
3163 if (nonPrimitiveTypeOverridesEquals(constant)) {
3164 compiler.reportWarning(match.expression,
3165 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS.error());
3166 failure = true;
3167 }
3168 } else {
3169 DartType constantType =
3170 constant.computeType(compiler.constantHandler);
3171 if (constantType != firstConstantType) {
3172 compiler.reportWarning(match.expression,
3173 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL.error());
3174 failure = true;
3175 }
3176 }
3151 constants[labelOrCase] = constant; 3177 constants[labelOrCase] = constant;
3152 } else { 3178 } else {
3153 // We don't handle labels yet. 3179 compiler.reportWarning(node, "Unsupported: Labels on cases");
3154 return false; 3180 failure = true;
3155 } 3181 }
3156 } 3182 }
3157 } 3183 }
3184 if (failure) {
3185 return false;
3186 }
3187
3158 // TODO(ngeoffray): Handle switch-instruction in bailout code. 3188 // TODO(ngeoffray): Handle switch-instruction in bailout code.
3159 work.allowSpeculativeOptimization = false; 3189 work.allowSpeculativeOptimization = false;
3160 // Then build a switch structure. 3190 // Then build a switch structure.
3161 HBasicBlock expressionStart = openNewBlock(); 3191 HBasicBlock expressionStart = openNewBlock();
3162 visit(node.expression); 3192 visit(node.expression);
3163 HInstruction expression = pop(); 3193 HInstruction expression = pop();
3164 if (node.cases.isEmpty()) { 3194 if (node.cases.isEmpty()) {
3165 return true; 3195 return true;
3166 } 3196 }
3167 HBasicBlock expressionEnd = current; 3197 HBasicBlock expressionEnd = current;
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
3259 statements, 3289 statements,
3260 hasDefault, 3290 hasDefault,
3261 jumpHandler.target, 3291 jumpHandler.target,
3262 jumpHandler.labels()), 3292 jumpHandler.labels()),
3263 joinBlock); 3293 joinBlock);
3264 3294
3265 jumpHandler.close(); 3295 jumpHandler.close();
3266 return true; 3296 return true;
3267 } 3297 }
3268 3298
3299 bool nonPrimitiveTypeOverridesEquals(Constant constant) {
3300 // Function values override equals. Even static ones, since
3301 // they inherit from [Function].
3302 if (constant.isFunction()) return true;
3303
3304 // [Map] and [List] do not override equals.
3305 // If constant is primitive, just return false. We know
3306 // about the equals methods of num/String classes.
3307 if (!constant.isConstructedObject()) return false;
3308
3309 ConstructedConstant constructedConstant = constant;
3310 DartType type = constructedConstant.type;
3311 assert(type !== null);
3312 Element element = type.element;
3313 // If the type is not a class, we'll just assume it overrides
3314 // operator==. Typedefs do, since [Function] does.
3315 if (!element.isClass()) return true;
3316 ClassElement classElement = element;
3317 return typeOverridesObjectEquals(classElement);
3318 }
3319
3320 bool typeOverridesObjectEquals(ClassElement classElement) {
3321 Element operatorEq =
3322 lookupOperator(classElement, const SourceString('=='));
3323 if (operatorEq == null) return false;
3324 // If the operator== declaration is in Object, it's not overridden.
3325 return (operatorEq.getEnclosingClass() != compiler.objectClass);
3326 }
3327
3328 Element lookupOperator(ClassElement classElement, SourceString operatorName) {
3329 SourceString dartMethodName =
3330 Elements.constructOperatorName(operatorName, false);
3331 return classElement.lookupMember(dartMethodName);
3332 }
3333
3269 3334
3270 // Recursively build an if/else structure to match the cases. 3335 // Recursively build an if/else structure to match the cases.
3271 void buildSwitchCases(Link<Node> cases, HInstruction expression, 3336 void buildSwitchCases(Link<Node> cases, HInstruction expression,
3272 [int encounteredCaseTypes = 0]) { 3337 [int encounteredCaseTypes = 0]) {
3273 final int NO_TYPE = 0; 3338 final int NO_TYPE = 0;
3274 final int INT_TYPE = 1; 3339 final int INT_TYPE = 1;
3275 final int STRING_TYPE = 2; 3340 final int STRING_TYPE = 2;
3276 final int CONFLICT_TYPE = 3; 3341 final int CONFLICT_TYPE = 3;
3277 int combine(int type1, int type2) => type1 | type2; 3342 int combine(int type1, int type2) => type1 | type2;
3278 3343
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
3319 Element equalsHelper = interceptors.getEqualsInterceptor(); 3384 Element equalsHelper = interceptors.getEqualsInterceptor();
3320 HInstruction target = new HStatic(equalsHelper); 3385 HInstruction target = new HStatic(equalsHelper);
3321 add(target); 3386 add(target);
3322 CaseMatch match = remainingCases.head; 3387 CaseMatch match = remainingCases.head;
3323 // TODO(lrn): Move the constant resolution to the resolver, so 3388 // TODO(lrn): Move the constant resolution to the resolver, so
3324 // we can report an error before reaching the backend. 3389 // we can report an error before reaching the backend.
3325 Constant constant = 3390 Constant constant =
3326 compiler.constantHandler.tryCompileNodeWithDefinitions( 3391 compiler.constantHandler.tryCompileNodeWithDefinitions(
3327 match.expression, elements); 3392 match.expression, elements);
3328 if (constant !== null) { 3393 if (constant !== null) {
3329 if (constant.isInt()) {
3330 // Report the first mixed-string/int type error only.
3331 if (encounteredCaseTypes == STRING_TYPE) {
3332 compiler.reportWarning(
3333 match, MessageKind.INVALID_CASE_EXPRESSION_TYPE);
3334 }
3335 encounteredCaseTypes = combine(encounteredCaseTypes, INT_TYPE);
3336 } else if (constant.isString()) {
3337 if (encounteredCaseTypes == INT_TYPE) {
3338 compiler.reportWarning(
3339 match, MessageKind.INVALID_CASE_EXPRESSION_TYPE);
3340 }
3341 encounteredCaseTypes = combine(encounteredCaseTypes, STRING_TYPE);
3342 } else {
3343 compiler.reportWarning(match,
3344 MessageKind.INVALID_CASE_EXPRESSION);
3345 encounteredCaseTypes = CONFLICT_TYPE;
3346 }
3347 stack.add(graph.addConstant(constant)); 3394 stack.add(graph.addConstant(constant));
3348 } else { 3395 } else {
3349 // TODO(lrn): Remove this else branch, and make the constant
3350 // evaluation mandatory when we are ready to break existing code using
3351 // non constant-int-or-string expressions.
3352 compiler.reportWarning(match,
3353 'case expressions not compile-time constant int or string.');
3354 visit(match.expression); 3396 visit(match.expression);
3355 encounteredCaseTypes = CONFLICT_TYPE;
3356 } 3397 }
3357 push(new HEquals(target, pop(), expression)); 3398 push(new HEquals(target, pop(), expression));
3358 } 3399 }
3359 3400
3360 // If this is the last expression, just return it. 3401 // If this is the last expression, just return it.
3361 Link<Node> tail = skipLabels(remainingCases.tail); 3402 Link<Node> tail = skipLabels(remainingCases.tail);
3362 if (tail.isEmpty()) { 3403 if (tail.isEmpty()) {
3363 left(); 3404 left();
3364 return; 3405 return;
3365 } 3406 }
(...skipping 573 matching lines...) Expand 10 before | Expand all | Expand 10 after
3939 new HSubGraphBlockInformation(elseBranch.graph)); 3980 new HSubGraphBlockInformation(elseBranch.graph));
3940 3981
3941 HBasicBlock conditionStartBlock = conditionBranch.block; 3982 HBasicBlock conditionStartBlock = conditionBranch.block;
3942 conditionStartBlock.setBlockFlow(info, joinBlock); 3983 conditionStartBlock.setBlockFlow(info, joinBlock);
3943 SubGraph conditionGraph = conditionBranch.graph; 3984 SubGraph conditionGraph = conditionBranch.graph;
3944 HIf branch = conditionGraph.end.last; 3985 HIf branch = conditionGraph.end.last;
3945 assert(branch is HIf); 3986 assert(branch is HIf);
3946 branch.blockInformation = conditionStartBlock.blockFlow; 3987 branch.blockInformation = conditionStartBlock.blockFlow;
3947 } 3988 }
3948 } 3989 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698