| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 library kernel.analyzer.ast_from_analyzer; | 4 library kernel.analyzer.ast_from_analyzer; |
| 5 | 5 |
| 6 import '../ast.dart' as ast; | 6 import '../ast.dart' as ast; |
| 7 import '../frontend/accessors.dart'; | 7 import '../frontend/accessors.dart'; |
| 8 import '../frontend/super_initializers.dart'; | 8 import '../frontend/super_initializers.dart'; |
| 9 import '../log.dart'; | 9 import '../log.dart'; |
| 10 import '../type_algebra.dart'; | 10 import '../type_algebra.dart'; |
| (...skipping 2322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2333 assert(defaultConstructor.enclosingElement == node.element); | 2333 assert(defaultConstructor.enclosingElement == node.element); |
| 2334 if (!defaultConstructor.isSynthetic) { | 2334 if (!defaultConstructor.isSynthetic) { |
| 2335 throw 'Non-synthetic default constructor not in list of members. ' | 2335 throw 'Non-synthetic default constructor not in list of members. ' |
| 2336 '${node} $element $defaultConstructor'; | 2336 '${node} $element $defaultConstructor'; |
| 2337 } | 2337 } |
| 2338 var memberNode = scope.getMemberReference(defaultConstructor); | 2338 var memberNode = scope.getMemberReference(defaultConstructor); |
| 2339 classNode.addMember(memberNode); | 2339 classNode.addMember(memberNode); |
| 2340 buildDefaultConstructor(memberNode, defaultConstructor); | 2340 buildDefaultConstructor(memberNode, defaultConstructor); |
| 2341 } | 2341 } |
| 2342 } | 2342 } |
| 2343 | |
| 2344 addDefaultFieldInitializers(classNode); | |
| 2345 } | 2343 } |
| 2346 | 2344 |
| 2347 void buildDefaultConstructor( | 2345 void buildDefaultConstructor( |
| 2348 ast.Constructor constructor, ConstructorElement element) { | 2346 ast.Constructor constructor, ConstructorElement element) { |
| 2349 var function = constructor.function; | 2347 var function = constructor.function; |
| 2350 function.body = new ast.EmptyStatement()..parent = function; | 2348 function.body = new ast.EmptyStatement()..parent = function; |
| 2351 var class_ = element.enclosingElement; | 2349 var class_ = element.enclosingElement; |
| 2352 if (class_.supertype != null) { | 2350 if (class_.supertype != null) { |
| 2353 // DESIGN TODO: If the super class is a mixin application, we will link to | 2351 // DESIGN TODO: If the super class is a mixin application, we will link to |
| 2354 // a constructor not in the immediate super class. This is a problem due | 2352 // a constructor not in the immediate super class. This is a problem due |
| 2355 // to the fact that mixed-in fields come with initializers which need to | 2353 // to the fact that mixed-in fields come with initializers which need to |
| 2356 // be executed by a constructor. The mixin transformer takes care of | 2354 // be executed by a constructor. The mixin transformer takes care of |
| 2357 // this by making forwarding constructors and the super initializers will | 2355 // this by making forwarding constructors and the super initializers will |
| 2358 // be rewritten to use them (see `transformations/mixin_full_resolution`). | 2356 // be rewritten to use them (see `transformations/mixin_full_resolution`). |
| 2359 var superConstructor = | 2357 var superConstructor = |
| 2360 scope.findDefaultConstructor(class_.supertype.element); | 2358 scope.findDefaultConstructor(class_.supertype.element); |
| 2361 var target = scope.resolveConstructor(superConstructor); | 2359 var target = scope.resolveConstructor(superConstructor); |
| 2362 if (target == null) { | 2360 if (target == null) { |
| 2363 constructor.initializers | 2361 constructor.initializers |
| 2364 .add(new ast.InvalidInitializer()..parent = constructor); | 2362 .add(new ast.InvalidInitializer()..parent = constructor); |
| 2365 } else { | 2363 } else { |
| 2366 var arguments = new ast.Arguments.empty(); | 2364 var arguments = new ast.Arguments.empty(); |
| 2367 constructor.initializers.add( | 2365 constructor.initializers.add( |
| 2368 new ast.SuperInitializer(target, arguments)..parent = constructor); | 2366 new ast.SuperInitializer(target, arguments)..parent = constructor); |
| 2369 } | 2367 } |
| 2370 } | 2368 } |
| 2371 } | 2369 } |
| 2372 | 2370 |
| 2373 /// Adds initializers to fields that are have no initializer and are not | |
| 2374 /// initialized by all constructors in the class. | |
| 2375 void addDefaultFieldInitializers(ast.Class node) { | |
| 2376 List<ast.Field> uninitializedFields = new List<ast.Field>(); | |
| 2377 for (var field in node.fields) { | |
| 2378 if (field.initializer != null || field.isExternal) continue; | |
| 2379 if (field.isStatic) { | |
| 2380 field.initializer = new ast.NullLiteral()..parent = field; | |
| 2381 } else { | |
| 2382 uninitializedFields.add(field); | |
| 2383 } | |
| 2384 } | |
| 2385 if (uninitializedFields.isEmpty) return; | |
| 2386 constructorLoop: | |
| 2387 for (var constructor in node.constructors) { | |
| 2388 var remainingFields = uninitializedFields.toSet(); | |
| 2389 for (var initializer in constructor.initializers) { | |
| 2390 if (initializer is ast.FieldInitializer) { | |
| 2391 remainingFields.remove(initializer.field); | |
| 2392 } else if (initializer is ast.RedirectingInitializer) { | |
| 2393 // The target constructor will be checked in another iteration. | |
| 2394 continue constructorLoop; | |
| 2395 } | |
| 2396 } | |
| 2397 for (var field in remainingFields) { | |
| 2398 if (field.initializer == null) { | |
| 2399 field.initializer = new ast.NullLiteral()..parent = field; | |
| 2400 } | |
| 2401 } | |
| 2402 } | |
| 2403 } | |
| 2404 | |
| 2405 /// True for the `values` field of an `enum` class. | 2371 /// True for the `values` field of an `enum` class. |
| 2406 static bool _isValuesField(FieldElement field) => field.name == 'values'; | 2372 static bool _isValuesField(FieldElement field) => field.name == 'values'; |
| 2407 | 2373 |
| 2408 /// True for the `index` field of an `enum` class. | 2374 /// True for the `index` field of an `enum` class. |
| 2409 static bool _isIndexField(FieldElement field) => field.name == 'index'; | 2375 static bool _isIndexField(FieldElement field) => field.name == 'index'; |
| 2410 | 2376 |
| 2411 visitEnumDeclaration(EnumDeclaration node) { | 2377 visitEnumDeclaration(EnumDeclaration node) { |
| 2412 addAnnotations(node.metadata); | 2378 addAnnotations(node.metadata); |
| 2413 ast.Class classNode = currentClass; | 2379 ast.Class classNode = currentClass; |
| 2414 var intType = | 2380 var intType = |
| (...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2756 if (element is FieldElement) return element.getter; | 2722 if (element is FieldElement) return element.getter; |
| 2757 return element; | 2723 return element; |
| 2758 } | 2724 } |
| 2759 | 2725 |
| 2760 Element desynthesizeSetter(Element element) { | 2726 Element desynthesizeSetter(Element element) { |
| 2761 if (element == null || !element.isSynthetic) return element; | 2727 if (element == null || !element.isSynthetic) return element; |
| 2762 if (element is PropertyAccessorElement) return element.variable; | 2728 if (element is PropertyAccessorElement) return element.variable; |
| 2763 if (element is FieldElement) return element.setter; | 2729 if (element is FieldElement) return element.setter; |
| 2764 return element; | 2730 return element; |
| 2765 } | 2731 } |
| OLD | NEW |