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

Side by Side Diff: frog/member.dart

Issue 9146001: continued cleanup of initialization and Value (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: touchups to comments Created 8 years, 11 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
« frog/gen.dart ('K') | « frog/gen.dart ('k') | frog/minfrog » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 /** A formal parameter to a [Method]. */ 5 /** A formal parameter to a [Method]. */
6 class Parameter { 6 class Parameter {
7 FormalNode definition; 7 FormalNode definition;
8 Member method; 8 Member method;
9 9
10 String name; 10 String name;
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 world.error( 361 world.error(
362 'non constant static field must be initialized in functions', 362 'non constant static field must be initialized in functions',
363 value.span); 363 value.span);
364 } else { 364 } else {
365 world.error( 365 world.error(
366 'non constant field must be initialized in constructor', 366 'non constant field must be initialized in constructor',
367 value.span); 367 value.span);
368 } 368 }
369 } 369 }
370 370
371
371 if (isStatic) { 372 if (isStatic) {
372 _computedValue = world.gen.globalForStaticField( 373 if (isFinal && _computedValue.isConst) {
373 this, _computedValue, [_computedValue]); 374 ; // keep const as is here
375 } else {
376 _computedValue = world.gen.globalForStaticField(
377 this, _computedValue, [_computedValue]);
378 }
374 } 379 }
375 _computing = false; 380 _computing = false;
376 } 381 }
377 return _computedValue; 382 return _computedValue;
378 } 383 }
379 384
380 Value _get(MethodGenerator context, Node node, Value target, 385 Value _get(MethodGenerator context, Node node, Value target,
381 [bool isDynamic=false]) { 386 [bool isDynamic=false]) {
382 if (isNative && returnType != null) { 387 if (isNative && returnType != null) {
383 returnType.markUsed(); 388 returnType.markUsed();
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 return new Value(inferredResult, ret.code, node.span); 645 return new Value(inferredResult, ret.code, node.span);
641 } 646 }
642 647
643 Value _set(MethodGenerator context, Node node, Value target, Value value, 648 Value _set(MethodGenerator context, Node node, Value target, Value value,
644 [bool isDynamic=false]) { 649 [bool isDynamic=false]) {
645 // TODO(jimhug): Check arg types in context of concrete type. 650 // TODO(jimhug): Check arg types in context of concrete type.
646 Value ret = baseMember._set(context, node, target, value, isDynamic); 651 Value ret = baseMember._set(context, node, target, value, isDynamic);
647 return new Value(returnType, ret.code, node.span); 652 return new Value(returnType, ret.code, node.span);
648 } 653 }
649 654
655 _evalConstConstructor(ObjectValue newObject, Arguments args) {
656 // TODO(jimhug): Concrete type probably matters somehow here
657 return baseMember.dynamic._evalConstConstructor(newObject, args);
658 }
659
660
650 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, 661 Value invoke(MethodGenerator context, Node node, Value target, Arguments args,
651 [bool isDynamic=false]) { 662 [bool isDynamic=false]) {
652 // TODO(jimhug): Check arg types in context of concrete type. 663 // TODO(jimhug): Check arg types in context of concrete type.
653 Value ret = baseMember.invoke(context, node, target, args, isDynamic); 664 Value ret = baseMember.invoke(context, node, target, args, isDynamic);
654 var code = ret.code; 665 var code = ret.code;
655 if (isConstructor) { 666 if (isConstructor) {
656 // TODO(jimhug): Egregious hack - won't live through the year. 667 // TODO(jimhug): Egregious hack - won't live through the year.
657 code = code.replaceFirst( 668 code = code.replaceFirst(
658 declaringType.genericType.jsname, declaringType.jsname); 669 declaringType.genericType.jsname, declaringType.jsname);
659 } 670 }
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after
1007 } 1018 }
1008 1019
1009 if (isFactory) { 1020 if (isFactory) {
1010 assert(target.isType); 1021 assert(target.isType);
1011 return new Value(target.type, '$generatedFactoryName($argsString)', 1022 return new Value(target.type, '$generatedFactoryName($argsString)',
1012 node !== null ? node.span : null); 1023 node !== null ? node.span : null);
1013 } 1024 }
1014 1025
1015 if (isStatic) { 1026 if (isStatic) {
1016 if (declaringType.isTop) { 1027 if (declaringType.isTop) {
1017 // TODO(jimhug): Explore moving libraries into their own namespaces
1018 return new Value(inferredResult, 1028 return new Value(inferredResult,
1019 '$jsname($argsString)', node !== null ? node.span : null); 1029 '$jsname($argsString)', node !== null ? node.span : null);
1020 } 1030 }
1021 return new Value(inferredResult, 1031 return new Value(inferredResult,
1022 '${declaringType.jsname}.$jsname($argsString)', node.span); 1032 '${declaringType.jsname}.$jsname($argsString)', node.span);
1023 } 1033 }
1024 1034
1025 var code = '${target.code}.$jsname($argsString)';
1026 // optimize expressions which we know statically their value.
1027 // ????
1028 /*
1029 if (target.isConst) {
1030 if (target is GlobalValue) {
1031 target = target.dynamic.exp; // TODO: an inline "cast" would be nice.
1032 }
1033 if (name == 'get:length') {
1034 if (target is ConstListValue || target is ConstMapValue) {
1035 code = '${target.dynamic.values.length}';
1036 }
1037 } else if (name == 'isEmpty') {
1038 if (target is ConstListValue || target is ConstMapValue) {
1039 code = '${target.dynamic.values.isEmpty()}';
1040 }
1041 }
1042 }
1043 */
1044
1045 // TODO(jmesserly): factor this better 1035 // TODO(jmesserly): factor this better
1046 if (name == 'get:typeName' && declaringType.library.isDom) { 1036 if (name == 'get:typeName' && declaringType.library.isDom) {
1047 world.gen.corejs.ensureTypeNameOf(); 1037 world.gen.corejs.ensureTypeNameOf();
1048 } 1038 }
1049 1039
1040 var code = '${target.code}.$jsname($argsString)';
1050 return new Value(inferredResult, code, node.span); 1041 return new Value(inferredResult, code, node.span);
1051 } 1042 }
1052 1043
1053 Value _invokeConstructor(MethodGenerator context, Node node, 1044 Value _invokeConstructor(MethodGenerator context, Node node,
1054 Value target, Arguments args, argsString) { 1045 Value target, Arguments args, argsString) {
1055 declaringType.markUsed(); 1046 declaringType.markUsed();
1056 1047
1057 String ctor = constructorName; 1048 String ctor = constructorName;
1058 if (ctor != '') ctor = '.${ctor}\$ctor'; 1049 if (ctor != '') ctor = '.${ctor}\$ctor';
1059 1050
1051 final span = node != null ? node.span : target.span;
1060 if (!target.isType) { 1052 if (!target.isType) {
1061 // initializer call to another constructor 1053 // initializer call to another constructor
1062 var code = '${declaringType.nativeName}${ctor}.call($argsString)'; 1054 var code = '${declaringType.nativeName}${ctor}.call($argsString)';
1063 return new Value(target.type, code, node.span); 1055 return new Value(target.type, code, span);
1064 } else { 1056 } else {
1065 var code = 'new ${declaringType.nativeName}${ctor}($argsString)'; 1057 // Start of abstract interpretation to replace const hacks goes here
1066
1067 // TODO(jmesserly): using the "node" here feels really hacky 1058 // TODO(jmesserly): using the "node" here feels really hacky
1068 if (isConst && node is NewExpression && node.dynamic.isConst) { 1059 if (isConst && node is NewExpression && node.dynamic.isConst) {
1069 return _invokeConstConstructor(node, code, target, args); 1060 // !!!!!! Egregious hack !!!!!!!
1061 if (isNative || declaringType.name == 'JSSyntaxRegExp') {
1062 // check that all args are const?
1063 var code = 'new ${declaringType.nativeName}${ctor}($argsString)';
1064 return world.gen.globalForConst(new Value(target.type, code, span),
1065 [args.values]);
1066 }
1067 var newType = declaringType;
1068 var newObject = new ObjectValue(true, newType, span);
1069 newObject.initFields();
1070 _evalConstConstructor(newObject, args);
1071 // ??? Does args.values include named args???
Jennifer Messerly 2012/01/09 20:45:35 add a TODO here?
jimhug 2012/01/09 21:12:17 I've figured out the answer - so I'll remove the c
1072 return world.gen.globalForConst(newObject, [args.values]);
1070 } else { 1073 } else {
1071 final span = node != null ? node.span : target.span; 1074 var code = 'new ${declaringType.nativeName}${ctor}($argsString)';
1072 return new Value(target.type, code, span); 1075 return new Value(target.type, code, span);
1073 } 1076 }
1074 } 1077 }
1075 } 1078 }
1076 1079
1077 /** 1080 _evalConstConstructor(Value newObject, Arguments args) {
1078 * Special handling for const constructors so that so that: 1081 declaringType.markUsed();
1079 * [: const B() === const B.a(0, 1) === const B.b(0) :] 1082 var generator = new MethodGenerator(this, null);
1080 * where: [: 1083 generator.evalBody(newObject, args);
1081 * class A {
1082 * final int x;
1083 * const A(this.x);
1084 * }
1085 *
1086 * class B {
1087 * final int y;
1088 * const B() : y = 0, super(1);
1089 * const B.a(this.y, x) : super(x);
1090 * const B.b(v) : this.a(v, 1);
1091 * }
1092 * :]
1093 */
1094 Value _invokeConstConstructor(
1095 Node node, String code, Value target, Arguments args) {
1096 // TODO(jimhug): This should be low-hanging fruit for abstract eval!
1097
1098 // Statically compute the actual value for every field in the const object.
1099 final fields = new Map<String, Value>();
1100
1101 // First deduce the value for fields initialized with the 'this.x' syntax.
1102 for (int i = 0; i < parameters.length; i++) {
1103 var param = parameters[i];
1104 if (param.isInitializer) {
1105 var value = null;
1106 if (i < args.length) {
1107 value = args.values[i];
1108 } else { // named arguments
1109 value = args.getValue(param.name);
1110 if (value == null) {
1111 value = param.value;
1112 }
1113 }
1114 fields[param.name] = value.constValue;
1115 }
1116 }
1117
1118 // Then evaluate initializer expressions.
1119 if (definition.initializers != null) {
1120 // Introduce a temporary scope to evaluate initializers, which defines the
1121 // value for any formal argument as it's constant expression value.
1122 generator._pushBlock();
1123 for (int j = 0; j < definition.formals.length; j++) {
1124 var name = definition.formals[j].name.name;
1125 var value = null;
1126 if (j < args.length) {
1127 value = args.values[j];
1128 } else { // named arguments
1129 value = args.getValue(parameters[j].name);
1130 if (value == null) {
1131 value = parameters[j].value;
1132 }
1133 }
1134 generator._scope._vars[name] = value;
1135 }
1136
1137 // TODO(jmesserly): unify with initializer code in gen.dart
1138 for (var init in definition.initializers) {
1139 if (init is CallExpression) {
1140 // Construct arguments to delegate and invoke it.
1141 var delegateArgs = generator._makeArgs(init.arguments);
1142 var value = initDelegate.invoke(
1143 generator, node, target, delegateArgs);
1144 if (init.target is ThisExpression) {
1145 // Redirection: Use directly the delegate result. E.g. so that
1146 // const B.b(0) === const B.a(0, 1)
1147 return value;
1148 } else {
1149 // Super-call: embed the value the super class fields.
1150 value = value.constValue;
1151 for (var fname in value.fields.getKeys()) {
1152 fields[fname] = value.fields[fname];
1153 }
1154 }
1155 } else {
1156 // Normal field initializer assignment.
1157 BinaryExpression assign = init;
1158 var x = assign.x; // DotExpression or VarExpression
1159 var fname = x.name.name;
1160 var val = generator.visitValue(assign.y);
1161 if (!val.isConst) {
1162 world.error('invalid non-const initializer in const constructor',
1163 assign.y.span);
1164 }
1165 fields[fname] = val;
1166 }
1167 }
1168
1169 generator._popBlock();
1170 }
1171
1172 // Add default values only if they weren't overriden in the constructor.
1173 for (var f in declaringType.members.getValues()) {
1174 if (f is FieldMember && !f.isStatic && !fields.containsKey(f.name)) {
1175 if (!f.isFinal) {
1176 world.error('const class "${declaringType.name}" has non-final '
1177 + 'field "${f.name}"', f.span);
1178 }
1179 if (f.value != null) {
1180 fields[f.name] = f.computeValue();
1181 }
1182 }
1183 }
1184
1185 return world.gen.globalForConst(
1186 new ObjectValue(fields, true, target.type, code, node.span),
1187 args.values);
1188 } 1084 }
1189 1085
1190
1191 Value _invokeBuiltin(MethodGenerator context, Node node, Value target, 1086 Value _invokeBuiltin(MethodGenerator context, Node node, Value target,
1192 Arguments args, argsCode, bool isDynamic) { 1087 Arguments args, argsCode, bool isDynamic) {
1193 var allConst = target.isConst && args.values.every((arg) => arg.isConst);
1194
1195 // Handle some fast paths for Number, String, List and DOM. 1088 // Handle some fast paths for Number, String, List and DOM.
1196 if (declaringType.isNum) { 1089 if (declaringType.isNum) {
1197 // TODO(jimhug): This fails in bad ways when argsCode[1] is not num. 1090 // TODO(jimhug): This fails in bad ways when argsCode[1] is not num.
1198 // TODO(jimhug): What about null? 1091 // TODO(jimhug): What about null?
1199 if (!allConst) { 1092 var code;
1200 var code; 1093 if (name == ':negate') {
1201 if (name == ':negate') { 1094 code = '-${target.code}';
1202 code = '-${target.code}'; 1095 } else if (name == ':bit_not') {
1203 } else if (name == ':bit_not') { 1096 code = '~${target.code}';
1204 code = '~${target.code}'; 1097 } else if (name == ':truncdiv' || name == ':mod') {
1205 } else if (name == ':truncdiv' || name == ':mod') { 1098 world.gen.corejs.useOperator(name);
1206 world.gen.corejs.useOperator(name); 1099 code = '$jsname(${target.code}, ${argsCode[0]})';
1207 code = '$jsname(${target.code}, ${argsCode[0]})'; 1100 } else {
1208 } else { 1101 var op = TokenKind.rawOperatorFromMethod(name);
1209 var op = TokenKind.rawOperatorFromMethod(name); 1102 code = '${target.code} $op ${argsCode[0]}';
1210 code = '${target.code} $op ${argsCode[0]}'; 1103 }
1211 }
1212 1104
1213 return new Value(inferredResult, code, node.span); 1105 return new Value(inferredResult, code, node.span);
1214 } else {
1215 var value;
1216 num val0, val1, ival0, ival1;
1217 val0 = target.dynamic.actualValue;
1218 ival0 = val0.toInt();
1219 if (args.values.length > 0) {
1220 val1 = args.values[0].dynamic.actualValue;
1221 ival1 = val1.toInt();
1222 }
1223 switch (name) {
1224 case ':negate': value = -val0; break;
1225 case ':add': value = val0 + val1; break;
1226 case ':sub': value = val0 - val1; break;
1227 case ':mul': value = val0 * val1; break;
1228 case ':div': value = val0 / val1; break;
1229 case ':truncdiv': value = val0 ~/ val1; break;
1230 case ':mod': value = val0 % val1; break;
1231 case ':eq': value = val0 == val1; break;
1232 case ':lt': value = val0 < val1; break;
1233 case ':gt': value = val0 > val1; break;
1234 case ':lte': value = val0 <= val1; break;
1235 case ':gte': value = val0 >= val1; break;
1236 case ':ne': value = val0 != val1; break;
1237
1238 // Note: unfortunatelly bit operations fail on doubles in dartvm
1239 case ':bit_not': value = (~ival0).toDouble(); break;
1240 case ':bit_or': value = (ival0 | ival1).toDouble(); break;
1241 case ':bit_xor': value = (ival0 ^ ival1).toDouble(); break;
1242 case ':bit_and': value = (ival0 & ival1).toDouble(); break;
1243 case ':shl': value = (ival0 << ival1).toDouble(); break;
1244 case ':sar': value = (ival0 >> ival1).toDouble(); break;
1245 case ':shr': value = (ival0 >>> ival1).toDouble(); break;
1246 }
1247 if (inferredResult.isInt) {
1248 return Value.fromInt(value.toInt(), node.span);
1249 } else if (inferredResult.isDouble) {
1250 return Value.fromDouble(value.toDouble(), node.span);
1251 } else if (inferredResult.isNum) {
1252 // TODO(jimhug): Number type system is flawed here...
1253 return Value.fromDouble(value.toDouble(), node.span);
1254 } else if (inferredResult.isBool) {
1255 return Value.fromBool(value, node.span);
1256 } else {
1257 world.internalError(
1258 'unsupported const result type "${inferredResult.name}"',
1259 node.span);
1260 }
1261 }
1262 } else if (declaringType.isString) { 1106 } else if (declaringType.isString) {
1263 if (name == ':index') { 1107 if (name == ':index') {
1264 // Note: this could technically propagate constness, but that's not
1265 // specified explicitly and the VM doesn't do that.
1266 return new Value(declaringType, '${target.code}[${argsCode[0]}]', 1108 return new Value(declaringType, '${target.code}[${argsCode[0]}]',
1267 node.span); 1109 node.span);
1268 } else if (name == ':add') { 1110 } else if (name == ':add') {
1269 if (allConst) {
1270 final value = target.dynamic.actualValue +
1271 args.values[0].dynamic.actualValue;
1272 return Value.fromString(value, node.span);
1273 }
1274
1275 return new Value(declaringType, '${target.code} + ${argsCode[0]}', 1111 return new Value(declaringType, '${target.code} + ${argsCode[0]}',
1276 node.span); 1112 node.span);
1277 } 1113 }
1278 } else if (declaringType.isNative) { 1114 } else if (declaringType.isNative) {
1279 if (name == ':index') { 1115 if (name == ':index') {
1280 // Note: this could technically propagate constness, but that's not
1281 // specified explicitly and the VM doesn't do that.
1282 return 1116 return
1283 new Value(returnType, '${target.code}[${argsCode[0]}]', node.span); 1117 new Value(returnType, '${target.code}[${argsCode[0]}]', node.span);
1284 } else if (name == ':setindex') { 1118 } else if (name == ':setindex') {
1285 return new Value(returnType, 1119 return new Value(returnType,
1286 '${target.code}[${argsCode[0]}] = ${argsCode[1]}', node.span); 1120 '${target.code}[${argsCode[0]}] = ${argsCode[1]}', node.span);
1287 } 1121 }
1288 } 1122 }
1289 1123
1290 // TODO(jimhug): Optimize null on lhs as well. 1124 // TODO(jimhug): Optimize null on lhs as well.
1291 if (name == ':eq' || name == ':ne') { 1125 if (name == ':eq' || name == ':ne') {
1292 final op = name == ':eq' ? '==' : '!='; 1126 final op = name == ':eq' ? '==' : '!=';
1293 1127
1294 if (name == ':ne') { 1128 if (name == ':ne') {
1295 // Ensure == is generated. 1129 // Ensure == is generated.
1296 target.invoke(context, ':eq', node, args, isDynamic); 1130 target.invoke(context, ':eq', node, args, isDynamic);
1297 } 1131 }
1298 1132
1299 if (allConst) {
1300 var val0 = target.dynamic.actualValue;
1301 var val1 = args.values[0].dynamic.actualValue;
1302 var newVal = name == ':eq' ? val0 == val1 : val0 != val1;
1303 return Value.fromBool(newVal, node.span);
1304 }
1305 // Optimize test when null is on the rhs. 1133 // Optimize test when null is on the rhs.
1306 if (argsCode[0] == 'null') { 1134 if (argsCode[0] == 'null') {
1307 return new Value(inferredResult, '${target.code} $op null', node.span); 1135 return new Value(inferredResult, '${target.code} $op null', node.span);
1308 } else if (target.type.isNum || target.type.isString) { 1136 } else if (target.type.isNum || target.type.isString) {
1309 // TODO(jimhug): Maybe check rhs. 1137 // TODO(jimhug): Maybe check rhs.
1310 return new Value(inferredResult, '${target.code} $op ${argsCode[0]}', 1138 return new Value(inferredResult, '${target.code} $op ${argsCode[0]}',
1311 node.span); 1139 node.span);
1312 } 1140 }
1313 world.gen.corejs.useOperator(name); 1141 world.gen.corejs.useOperator(name);
1142 // TODO(jimhug): Should be able to use faster path sometimes here!
1314 return new Value(inferredResult, 1143 return new Value(inferredResult,
1315 '$jsname(${target.code}, ${argsCode[0]})', node.span); 1144 '$jsname(${target.code}, ${argsCode[0]})', node.span);
1316 } 1145 }
1317 1146
1318 if (isCallMethod) { 1147 if (isCallMethod) {
1319 declaringType.markUsed(); 1148 declaringType.markUsed();
1320 return new Value(inferredResult, 1149 return new Value(inferredResult,
1321 '${target.code}(${Strings.join(argsCode, ", ")})', node.span); 1150 '${target.code}(${Strings.join(argsCode, ", ")})', node.span);
1322 } 1151 }
1323 1152
1324 if (name == ':index') { 1153 if (name == ':index') {
1325 world.gen.corejs.useIndex = true; 1154 world.gen.corejs.useIndex = true;
1326 } else if (name == ':setindex') { 1155 } else if (name == ':setindex') {
1327 world.gen.corejs.useSetIndex = true; 1156 world.gen.corejs.useSetIndex = true;
1328 } 1157 }
1329 1158
1330 // Fall back to normal method invocation. 1159 // Fall back to normal method invocation.
1331 var argsString = Strings.join(argsCode, ', '); 1160 var argsString = Strings.join(argsCode, ', ');
1332 return new Value(inferredResult, '${target.code}.$jsname($argsString)', 1161 return new Value(inferredResult, '${target.code}.$jsname($argsString)',
1333 node.span); 1162 node.span);
1334 } 1163 }
1335 1164
1336 resolve() { 1165 resolve() {
1337 // TODO(jimhug): cut-and-paste-and-edit from Field.resolve 1166 // TODO(jimhug): work through side-by-side with spec
1338 isStatic = declaringType.isTop; 1167 isStatic = declaringType.isTop;
1339 isConst = false; 1168 isConst = false;
1340 isFactory = false; 1169 isFactory = false;
1341 isAbstract = !declaringType.isClass; 1170 isAbstract = !declaringType.isClass;
1342 if (definition.modifiers != null) { 1171 if (definition.modifiers != null) {
1343 for (var mod in definition.modifiers) { 1172 for (var mod in definition.modifiers) {
1344 if (mod.kind == TokenKind.STATIC) { 1173 if (mod.kind == TokenKind.STATIC) {
1345 if (isStatic) { 1174 if (isStatic) {
1346 world.error('duplicate static modifier', mod.span); 1175 world.error('duplicate static modifier', mod.span);
1347 } 1176 }
1348 isStatic = true; 1177 isStatic = true;
1349 } else if (isConstructor && mod.kind == TokenKind.CONST) { 1178 } else if (isConstructor && mod.kind == TokenKind.CONST) {
1350 if (isConst) { 1179 if (isConst) {
1351 world.error('duplicate const modifier', mod.span); 1180 world.error('duplicate const modifier', mod.span);
1352 } 1181 }
1182 if (isFactory) {
1183 world.error('const factory not allowed', mod.span);
1184 }
1353 isConst = true; 1185 isConst = true;
1354 } else if (mod.kind == TokenKind.FACTORY) { 1186 } else if (mod.kind == TokenKind.FACTORY) {
1355 if (isFactory) { 1187 if (isFactory) {
1356 world.error('duplicate factory modifier', mod.span); 1188 world.error('duplicate factory modifier', mod.span);
1357 } 1189 }
1190 if (isConst) {
1191 world.error('const factory not allowed', mod.span);
1192 }
1193 if (isStatic) {
1194 world.error('static factory not allowed', mod.span);
1195 }
1358 isFactory = true; 1196 isFactory = true;
1359 } else if (mod.kind == TokenKind.ABSTRACT) { 1197 } else if (mod.kind == TokenKind.ABSTRACT) {
1360 if (isAbstract) { 1198 if (isAbstract) {
1361 if (declaringType.isClass) { 1199 if (declaringType.isClass) {
1362 world.error('duplicate abstract modifier', mod.span); 1200 world.error('duplicate abstract modifier', mod.span);
1363 } else if (!isCallMethod) { 1201 } else if (!isCallMethod) {
1364 world.error('abstract modifier not allowed on interface members', 1202 world.error('abstract modifier not allowed on interface members',
1365 mod.span); 1203 mod.span);
1366 } 1204 }
1367 } 1205 }
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after
1752 } 1590 }
1753 1591
1754 void forEach(void f(Member member)) { 1592 void forEach(void f(Member member)) {
1755 factories.forEach((_, Map constructors) { 1593 factories.forEach((_, Map constructors) {
1756 constructors.forEach((_, Member member) { 1594 constructors.forEach((_, Member member) {
1757 f(member); 1595 f(member);
1758 }); 1596 });
1759 }); 1597 });
1760 } 1598 }
1761 } 1599 }
OLDNEW
« frog/gen.dart ('K') | « frog/gen.dart ('k') | frog/minfrog » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698