| 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 | 4 |
| 5 library fasta.kernel_target; | 5 library fasta.kernel_target; |
| 6 | 6 |
| 7 import 'dart:async' show Future; | 7 import 'dart:async' show Future; |
| 8 | 8 |
| 9 import 'dart:io' show File; | 9 import 'dart:io' show File; |
| 10 | 10 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 import '../source/source_loader.dart' show SourceLoader; | 47 import '../source/source_loader.dart' show SourceLoader; |
| 48 | 48 |
| 49 import '../source/source_class_builder.dart' show SourceClassBuilder; | 49 import '../source/source_class_builder.dart' show SourceClassBuilder; |
| 50 | 50 |
| 51 import '../target_implementation.dart' show TargetImplementation; | 51 import '../target_implementation.dart' show TargetImplementation; |
| 52 | 52 |
| 53 import '../translate_uri.dart' show TranslateUri; | 53 import '../translate_uri.dart' show TranslateUri; |
| 54 | 54 |
| 55 import '../dill/dill_target.dart' show DillTarget; | 55 import '../dill/dill_target.dart' show DillTarget; |
| 56 | 56 |
| 57 import '../errors.dart' | 57 import '../deprecated_problems.dart' |
| 58 show InputError, internalError, reportCrash, resetCrashReporting; | 58 show |
| 59 deprecated_InputError, |
| 60 deprecated_internalProblem, |
| 61 reportCrash, |
| 62 resetCrashReporting; |
| 59 | 63 |
| 60 import '../util/relativize.dart' show relativizeUri; | 64 import '../util/relativize.dart' show relativizeUri; |
| 61 | 65 |
| 62 import '../compiler_context.dart' show CompilerContext; | 66 import '../compiler_context.dart' show CompilerContext; |
| 63 | 67 |
| 64 import 'kernel_builder.dart' | 68 import 'kernel_builder.dart' |
| 65 show | 69 show |
| 66 Builder, | 70 Builder, |
| 67 ClassBuilder, | 71 ClassBuilder, |
| 68 InvalidTypeBuilder, | 72 InvalidTypeBuilder, |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 KernelTarget( | 110 KernelTarget( |
| 107 this.fileSystem, DillTarget dillTarget, TranslateUri uriTranslator, | 111 this.fileSystem, DillTarget dillTarget, TranslateUri uriTranslator, |
| 108 [Map<String, Source> uriToSource]) | 112 [Map<String, Source> uriToSource]) |
| 109 : dillTarget = dillTarget, | 113 : dillTarget = dillTarget, |
| 110 uriToSource = uriToSource ?? CompilerContext.current.uriToSource, | 114 uriToSource = uriToSource ?? CompilerContext.current.uriToSource, |
| 111 super(dillTarget.ticker, uriTranslator, dillTarget.backendTarget) { | 115 super(dillTarget.ticker, uriTranslator, dillTarget.backendTarget) { |
| 112 resetCrashReporting(); | 116 resetCrashReporting(); |
| 113 loader = createLoader(); | 117 loader = createLoader(); |
| 114 } | 118 } |
| 115 | 119 |
| 116 void addError(file, int charOffset, String message) { | 120 void deprecated_addError(file, int charOffset, String message) { |
| 117 Uri uri = file is String ? Uri.parse(file) : file; | 121 Uri uri = file is String ? Uri.parse(file) : file; |
| 118 InputError error = new InputError(uri, charOffset, message); | 122 deprecated_InputError error = |
| 119 String formatterMessage = error.format(); | 123 new deprecated_InputError(uri, charOffset, message); |
| 124 String formatterMessage = error.deprecated_format(); |
| 120 print(formatterMessage); | 125 print(formatterMessage); |
| 121 errors.add(formatterMessage); | 126 errors.add(formatterMessage); |
| 122 } | 127 } |
| 123 | 128 |
| 124 SourceLoader<Library> createLoader() => | 129 SourceLoader<Library> createLoader() => |
| 125 new SourceLoader<Library>(fileSystem, this); | 130 new SourceLoader<Library>(fileSystem, this); |
| 126 | 131 |
| 127 void addSourceInformation( | 132 void addSourceInformation( |
| 128 Uri uri, List<int> lineStarts, List<int> sourceCode) { | 133 Uri uri, List<int> lineStarts, List<int> sourceCode) { |
| 129 String fileUri = relativizeUri(uri); | 134 String fileUri = relativizeUri(uri); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 142 } | 147 } |
| 143 } | 148 } |
| 144 return new KernelLibraryBuilder(uri, fileUri, loader, isPatch); | 149 return new KernelLibraryBuilder(uri, fileUri, loader, isPatch); |
| 145 } | 150 } |
| 146 | 151 |
| 147 void forEachDirectSupertype(ClassBuilder cls, void f(NamedTypeBuilder type)) { | 152 void forEachDirectSupertype(ClassBuilder cls, void f(NamedTypeBuilder type)) { |
| 148 TypeBuilder supertype = cls.supertype; | 153 TypeBuilder supertype = cls.supertype; |
| 149 if (supertype is NamedTypeBuilder) { | 154 if (supertype is NamedTypeBuilder) { |
| 150 f(supertype); | 155 f(supertype); |
| 151 } else if (supertype != null) { | 156 } else if (supertype != null) { |
| 152 internalError("Unhandled: ${supertype.runtimeType}"); | 157 deprecated_internalProblem("Unhandled: ${supertype.runtimeType}"); |
| 153 } | 158 } |
| 154 if (cls.interfaces != null) { | 159 if (cls.interfaces != null) { |
| 155 for (NamedTypeBuilder t in cls.interfaces) { | 160 for (NamedTypeBuilder t in cls.interfaces) { |
| 156 f(t); | 161 f(t); |
| 157 } | 162 } |
| 158 } | 163 } |
| 159 if (cls.library.loader == loader && | 164 if (cls.library.loader == loader && |
| 160 // TODO(ahe): Implement DillClassBuilder.mixedInType and remove the | 165 // TODO(ahe): Implement DillClassBuilder.mixedInType and remove the |
| 161 // above check. | 166 // above check. |
| 162 cls.mixedInType != null) { | 167 cls.mixedInType != null) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 cls.implementedTypes.clear(); | 212 cls.implementedTypes.clear(); |
| 208 cls.supertype = null; | 213 cls.supertype = null; |
| 209 cls.mixedInType = null; | 214 cls.mixedInType = null; |
| 210 builder.supertype = new KernelNamedTypeBuilder("Object", null, | 215 builder.supertype = new KernelNamedTypeBuilder("Object", null, |
| 211 builder.charOffset, builder.fileUri ?? Uri.parse(cls.fileUri)) | 216 builder.charOffset, builder.fileUri ?? Uri.parse(cls.fileUri)) |
| 212 ..builder = objectClassBuilder; | 217 ..builder = objectClassBuilder; |
| 213 builder.interfaces = null; | 218 builder.interfaces = null; |
| 214 builder.mixedInType = null; | 219 builder.mixedInType = null; |
| 215 } | 220 } |
| 216 | 221 |
| 217 void handleInputError(InputError error, | 222 void handleInputError(deprecated_InputError error, |
| 218 {bool isFullProgram, bool trimDependencies: false}) { | 223 {bool isFullProgram, bool trimDependencies: false}) { |
| 219 if (error != null) { | 224 if (error != null) { |
| 220 String message = error.format(); | 225 String message = error.deprecated_format(); |
| 221 print(message); | 226 print(message); |
| 222 errors.add(message); | 227 errors.add(message); |
| 223 } | 228 } |
| 224 program = erroneousProgram(isFullProgram); | 229 program = erroneousProgram(isFullProgram); |
| 225 } | 230 } |
| 226 | 231 |
| 227 @override | 232 @override |
| 228 Future<Program> buildOutlines({CanonicalName nameRoot}) async { | 233 Future<Program> buildOutlines({CanonicalName nameRoot}) async { |
| 229 if (loader.first == null) return null; | 234 if (loader.first == null) return null; |
| 230 try { | 235 try { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 242 installDefaultSupertypes(); | 247 installDefaultSupertypes(); |
| 243 installDefaultConstructors(sourceClasses); | 248 installDefaultConstructors(sourceClasses); |
| 244 loader.resolveConstructors(); | 249 loader.resolveConstructors(); |
| 245 loader.finishTypeVariables(objectClassBuilder); | 250 loader.finishTypeVariables(objectClassBuilder); |
| 246 program = | 251 program = |
| 247 link(new List<Library>.from(loader.libraries), nameRoot: nameRoot); | 252 link(new List<Library>.from(loader.libraries), nameRoot: nameRoot); |
| 248 loader.computeHierarchy(program); | 253 loader.computeHierarchy(program); |
| 249 loader.checkOverrides(sourceClasses); | 254 loader.checkOverrides(sourceClasses); |
| 250 loader.prepareInitializerInference(); | 255 loader.prepareInitializerInference(); |
| 251 loader.performInitializerInference(); | 256 loader.performInitializerInference(); |
| 252 } on InputError catch (e) { | 257 } on deprecated_InputError catch (e) { |
| 253 handleInputError(e, isFullProgram: false); | 258 handleInputError(e, isFullProgram: false); |
| 254 } catch (e, s) { | 259 } catch (e, s) { |
| 255 return reportCrash(e, s, loader?.currentUriForCrashReporting); | 260 return reportCrash(e, s, loader?.currentUriForCrashReporting); |
| 256 } | 261 } |
| 257 return program; | 262 return program; |
| 258 } | 263 } |
| 259 | 264 |
| 260 /// Build the kernel representation of the program loaded by this target. The | 265 /// Build the kernel representation of the program loaded by this target. The |
| 261 /// program will contain full bodies for the code loaded from sources, and | 266 /// program will contain full bodies for the code loaded from sources, and |
| 262 /// only references to the code loaded by the [DillTarget], which may or may | 267 /// only references to the code loaded by the [DillTarget], which may or may |
| (...skipping 23 matching lines...) Expand all Loading... |
| 286 finishAllConstructors(); | 291 finishAllConstructors(); |
| 287 loader.finishNativeMethods(); | 292 loader.finishNativeMethods(); |
| 288 runBuildTransformations(); | 293 runBuildTransformations(); |
| 289 | 294 |
| 290 if (verify) this.verify(); | 295 if (verify) this.verify(); |
| 291 if (errors.isNotEmpty) { | 296 if (errors.isNotEmpty) { |
| 292 handleInputError(null, | 297 handleInputError(null, |
| 293 isFullProgram: true, trimDependencies: trimDependencies); | 298 isFullProgram: true, trimDependencies: trimDependencies); |
| 294 } | 299 } |
| 295 handleRecoverableErrors(loader.unhandledErrors); | 300 handleRecoverableErrors(loader.unhandledErrors); |
| 296 } on InputError catch (e) { | 301 } on deprecated_InputError catch (e) { |
| 297 handleInputError(e, | 302 handleInputError(e, |
| 298 isFullProgram: true, trimDependencies: trimDependencies); | 303 isFullProgram: true, trimDependencies: trimDependencies); |
| 299 } catch (e, s) { | 304 } catch (e, s) { |
| 300 return reportCrash(e, s, loader?.currentUriForCrashReporting); | 305 return reportCrash(e, s, loader?.currentUriForCrashReporting); |
| 301 } | 306 } |
| 302 if (trimDependencies) trimDependenciesInProgram(); | 307 if (trimDependencies) trimDependenciesInProgram(); |
| 303 return program; | 308 return program; |
| 304 } | 309 } |
| 305 | 310 |
| 306 Future writeDepsFile(Uri output, Uri depsFile, | 311 Future writeDepsFile(Uri output, Uri depsFile, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 ticker.logMs("Wrote deps file"); | 352 ticker.logMs("Wrote deps file"); |
| 348 } | 353 } |
| 349 | 354 |
| 350 /// Adds a synthetic field named `#errors` to the main library that contains | 355 /// Adds a synthetic field named `#errors` to the main library that contains |
| 351 /// [recoverableErrors] formatted. | 356 /// [recoverableErrors] formatted. |
| 352 /// | 357 /// |
| 353 /// If [recoverableErrors] is empty, this method does nothing. | 358 /// If [recoverableErrors] is empty, this method does nothing. |
| 354 /// | 359 /// |
| 355 /// If there's no main library, this method uses [erroneousProgram] to | 360 /// If there's no main library, this method uses [erroneousProgram] to |
| 356 /// replace [program]. | 361 /// replace [program]. |
| 357 void handleRecoverableErrors(List<InputError> recoverableErrors) { | 362 void handleRecoverableErrors(List<deprecated_InputError> recoverableErrors) { |
| 358 if (recoverableErrors.isEmpty) return; | 363 if (recoverableErrors.isEmpty) return; |
| 359 KernelLibraryBuilder mainLibrary = loader.first; | 364 KernelLibraryBuilder mainLibrary = loader.first; |
| 360 if (mainLibrary == null) { | 365 if (mainLibrary == null) { |
| 361 program = erroneousProgram(true); | 366 program = erroneousProgram(true); |
| 362 return; | 367 return; |
| 363 } | 368 } |
| 364 List<Expression> expressions = <Expression>[]; | 369 List<Expression> expressions = <Expression>[]; |
| 365 for (InputError error in recoverableErrors) { | 370 for (deprecated_InputError error in recoverableErrors) { |
| 366 String message = error.format(); | 371 String message = error.deprecated_format(); |
| 367 errors.add(message); | 372 errors.add(message); |
| 368 expressions.add(new StringLiteral(message)); | 373 expressions.add(new StringLiteral(message)); |
| 369 } | 374 } |
| 370 mainLibrary.library.addMember(new Field(new Name("#errors"), | 375 mainLibrary.library.addMember(new Field(new Name("#errors"), |
| 371 initializer: new ListLiteral(expressions, isConst: true), | 376 initializer: new ListLiteral(expressions, isConst: true), |
| 372 isConst: true)); | 377 isConst: true)); |
| 373 } | 378 } |
| 374 | 379 |
| 375 Program erroneousProgram(bool isFullProgram) { | 380 Program erroneousProgram(bool isFullProgram) { |
| 376 Uri uri = loader.first?.uri ?? Uri.parse("error:error"); | 381 Uri uri = loader.first?.uri ?? Uri.parse("error:error"); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 /// >that is accessible to LM , C has an implicitly declared constructor | 475 /// >that is accessible to LM , C has an implicitly declared constructor |
| 471 /// >named q'i = [C/S]qi of the form q'i(ai1,...,aiki) : | 476 /// >named q'i = [C/S]qi of the form q'i(ai1,...,aiki) : |
| 472 /// >super(ai1,...,aiki);. | 477 /// >super(ai1,...,aiki);. |
| 473 TypeDeclarationBuilder supertype = builder; | 478 TypeDeclarationBuilder supertype = builder; |
| 474 while (supertype.isMixinApplication) { | 479 while (supertype.isMixinApplication) { |
| 475 SourceClassBuilder named = supertype; | 480 SourceClassBuilder named = supertype; |
| 476 TypeBuilder type = named.supertype; | 481 TypeBuilder type = named.supertype; |
| 477 if (type is NamedTypeBuilder) { | 482 if (type is NamedTypeBuilder) { |
| 478 supertype = type.builder; | 483 supertype = type.builder; |
| 479 } else { | 484 } else { |
| 480 internalError("Unhandled: ${type.runtimeType}"); | 485 deprecated_internalProblem("Unhandled: ${type.runtimeType}"); |
| 481 } | 486 } |
| 482 } | 487 } |
| 483 if (supertype is KernelClassBuilder) { | 488 if (supertype is KernelClassBuilder) { |
| 484 Map<TypeParameter, DartType> substitutionMap = | 489 Map<TypeParameter, DartType> substitutionMap = |
| 485 computeKernelSubstitutionMap( | 490 computeKernelSubstitutionMap( |
| 486 builder.getSubstitutionMap(supertype, builder.fileUri, | 491 builder.getSubstitutionMap(supertype, builder.fileUri, |
| 487 builder.charOffset, dynamicType), | 492 builder.charOffset, dynamicType), |
| 488 builder.parent); | 493 builder.parent); |
| 489 if (supertype.cls.constructors.isEmpty) { | 494 if (supertype.cls.constructors.isEmpty) { |
| 490 builder.addSyntheticConstructor(makeDefaultConstructor()); | 495 builder.addSyntheticConstructor(makeDefaultConstructor()); |
| 491 } else { | 496 } else { |
| 492 for (Constructor constructor in supertype.cls.constructors) { | 497 for (Constructor constructor in supertype.cls.constructors) { |
| 493 builder.addSyntheticConstructor(makeMixinApplicationConstructor( | 498 builder.addSyntheticConstructor(makeMixinApplicationConstructor( |
| 494 builder.cls.mixin, constructor, substitutionMap)); | 499 builder.cls.mixin, constructor, substitutionMap)); |
| 495 } | 500 } |
| 496 } | 501 } |
| 497 } else if (supertype is InvalidTypeBuilder) { | 502 } else if (supertype is InvalidTypeBuilder) { |
| 498 builder.addSyntheticConstructor(makeDefaultConstructor()); | 503 builder.addSyntheticConstructor(makeDefaultConstructor()); |
| 499 } else { | 504 } else { |
| 500 internalError("Unhandled: ${supertype.runtimeType}"); | 505 deprecated_internalProblem("Unhandled: ${supertype.runtimeType}"); |
| 501 } | 506 } |
| 502 } else { | 507 } else { |
| 503 /// >Iff no constructor is specified for a class C, it implicitly has a | 508 /// >Iff no constructor is specified for a class C, it implicitly has a |
| 504 /// >default constructor C() : super() {}, unless C is class Object. | 509 /// >default constructor C() : super() {}, unless C is class Object. |
| 505 // The superinitializer is installed below in [finishConstructors]. | 510 // The superinitializer is installed below in [finishConstructors]. |
| 506 builder.addSyntheticConstructor(makeDefaultConstructor()); | 511 builder.addSyntheticConstructor(makeDefaultConstructor()); |
| 507 } | 512 } |
| 508 } | 513 } |
| 509 | 514 |
| 510 Map<TypeParameter, DartType> computeKernelSubstitutionMap( | 515 Map<TypeParameter, DartType> computeKernelSubstitutionMap( |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 596 MemberBuilder constructorBuilder = member; | 601 MemberBuilder constructorBuilder = member; |
| 597 Constructor constructor = constructorBuilder.target; | 602 Constructor constructor = constructorBuilder.target; |
| 598 if (!constructorBuilder.isRedirectingGenerativeConstructor) { | 603 if (!constructorBuilder.isRedirectingGenerativeConstructor) { |
| 599 /// >If no superinitializer is provided, an implicit superinitializer | 604 /// >If no superinitializer is provided, an implicit superinitializer |
| 600 /// >of the form super() is added at the end of k’s initializer list, | 605 /// >of the form super() is added at the end of k’s initializer list, |
| 601 /// >unless the enclosing class is class Object. | 606 /// >unless the enclosing class is class Object. |
| 602 if (constructor.initializers.isEmpty) { | 607 if (constructor.initializers.isEmpty) { |
| 603 superTarget ??= defaultSuperConstructor(cls); | 608 superTarget ??= defaultSuperConstructor(cls); |
| 604 Initializer initializer; | 609 Initializer initializer; |
| 605 if (superTarget == null) { | 610 if (superTarget == null) { |
| 606 addError( | 611 deprecated_addError( |
| 607 constructor.enclosingClass.fileUri, | 612 constructor.enclosingClass.fileUri, |
| 608 constructor.fileOffset, | 613 constructor.fileOffset, |
| 609 "${cls.superclass.name} has no constructor that takes no" | 614 "${cls.superclass.name} has no constructor that takes no" |
| 610 " arguments."); | 615 " arguments."); |
| 611 initializer = new InvalidInitializer(); | 616 initializer = new InvalidInitializer(); |
| 612 } else { | 617 } else { |
| 613 initializer = | 618 initializer = |
| 614 new SuperInitializer(superTarget, new Arguments.empty()); | 619 new SuperInitializer(superTarget, new Arguments.empty()); |
| 615 } | 620 } |
| 616 constructor.initializers.add(initializer); | 621 constructor.initializers.add(initializer); |
| 617 initializer.parent = constructor; | 622 initializer.parent = constructor; |
| 618 } | 623 } |
| 619 if (constructor.function.body == null) { | 624 if (constructor.function.body == null) { |
| 620 /// >If a generative constructor c is not a redirecting constructor | 625 /// >If a generative constructor c is not a redirecting constructor |
| 621 /// >and no body is provided, then c implicitly has an empty body {}. | 626 /// >and no body is provided, then c implicitly has an empty body {}. |
| 622 /// We use an empty statement instead. | 627 /// We use an empty statement instead. |
| 623 constructor.function.body = new EmptyStatement(); | 628 constructor.function.body = new EmptyStatement(); |
| 624 constructor.function.body.parent = constructor.function; | 629 constructor.function.body.parent = constructor.function; |
| 625 } | 630 } |
| 626 List<FieldInitializer> myFieldInitializers = <FieldInitializer>[]; | 631 List<FieldInitializer> myFieldInitializers = <FieldInitializer>[]; |
| 627 for (Initializer initializer in constructor.initializers) { | 632 for (Initializer initializer in constructor.initializers) { |
| 628 if (initializer is FieldInitializer) { | 633 if (initializer is FieldInitializer) { |
| 629 myFieldInitializers.add(initializer); | 634 myFieldInitializers.add(initializer); |
| 630 } | 635 } |
| 631 } | 636 } |
| 632 fieldInitializers[constructor] = myFieldInitializers; | 637 fieldInitializers[constructor] = myFieldInitializers; |
| 633 if (constructor.isConst && nonFinalFields.isNotEmpty) { | 638 if (constructor.isConst && nonFinalFields.isNotEmpty) { |
| 634 addError(constructor.enclosingClass.fileUri, constructor.fileOffset, | 639 deprecated_addError( |
| 640 constructor.enclosingClass.fileUri, |
| 641 constructor.fileOffset, |
| 635 "Constructor is marked 'const' so all fields must be final."); | 642 "Constructor is marked 'const' so all fields must be final."); |
| 636 for (Field field in nonFinalFields) { | 643 for (Field field in nonFinalFields) { |
| 637 addError(constructor.enclosingClass.fileUri, field.fileOffset, | 644 deprecated_addError( |
| 645 constructor.enclosingClass.fileUri, |
| 646 field.fileOffset, |
| 638 "Field isn't final, but constructor is 'const'."); | 647 "Field isn't final, but constructor is 'const'."); |
| 639 } | 648 } |
| 640 nonFinalFields.clear(); | 649 nonFinalFields.clear(); |
| 641 } | 650 } |
| 642 } | 651 } |
| 643 }); | 652 }); |
| 644 Set<Field> initializedFields; | 653 Set<Field> initializedFields; |
| 645 fieldInitializers.forEach( | 654 fieldInitializers.forEach( |
| 646 (Constructor constructor, List<FieldInitializer> initializers) { | 655 (Constructor constructor, List<FieldInitializer> initializers) { |
| 647 Iterable<Field> fields = initializers.map((i) => i.field); | 656 Iterable<Field> fields = initializers.map((i) => i.field); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 728 } | 737 } |
| 729 for (Constructor constructor in superclass.constructors) { | 738 for (Constructor constructor in superclass.constructors) { |
| 730 if (constructor.name.name.isEmpty) { | 739 if (constructor.name.name.isEmpty) { |
| 731 return constructor.function.requiredParameterCount == 0 | 740 return constructor.function.requiredParameterCount == 0 |
| 732 ? constructor | 741 ? constructor |
| 733 : null; | 742 : null; |
| 734 } | 743 } |
| 735 } | 744 } |
| 736 return null; | 745 return null; |
| 737 } | 746 } |
| OLD | NEW |