| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library fasta.kernel_target; |
| 6 |
| 7 import 'dart:async' show |
| 8 Future; |
| 9 |
| 10 import 'dart:io' show |
| 11 File, |
| 12 IOSink; |
| 13 |
| 14 import 'package:kernel/ast.dart' show |
| 15 Arguments, |
| 16 AsyncMarker, |
| 17 Class, |
| 18 Constructor, |
| 19 EmptyStatement, |
| 20 Expression, |
| 21 ExpressionStatement, |
| 22 Field, |
| 23 FieldInitializer, |
| 24 FunctionNode, |
| 25 Initializer, |
| 26 InvalidInitializer, |
| 27 Library, |
| 28 Name, |
| 29 NamedExpression, |
| 30 NullLiteral, |
| 31 Procedure, |
| 32 ProcedureKind, |
| 33 Program, |
| 34 RedirectingInitializer, |
| 35 ReturnStatement, |
| 36 StaticGet, |
| 37 StringLiteral, |
| 38 SuperInitializer, |
| 39 Throw, |
| 40 VariableDeclaration, |
| 41 VariableGet, |
| 42 VoidType; |
| 43 |
| 44 import 'package:kernel/binary/ast_to_binary.dart' show |
| 45 BinaryPrinter; |
| 46 |
| 47 import 'package:kernel/text/ast_to_text.dart' show |
| 48 Printer; |
| 49 |
| 50 import 'package:kernel/transformations/mixin_full_resolution.dart' show |
| 51 MixinFullResolution, |
| 52 SuperInitializerResolutionTransformer; |
| 53 |
| 54 import '../source/source_loader.dart' show |
| 55 SourceLoader; |
| 56 |
| 57 import '../source/source_class_builder.dart' show |
| 58 SourceClassBuilder; |
| 59 |
| 60 import '../target_implementation.dart' show |
| 61 TargetImplementation; |
| 62 |
| 63 import '../translate_uri.dart' show |
| 64 TranslateUri; |
| 65 |
| 66 import '../dill/dill_target.dart' show |
| 67 DillTarget; |
| 68 |
| 69 import '../dill/dill_member_builder.dart' show |
| 70 DillMemberBuilder; |
| 71 |
| 72 import '../ast_kind.dart' show |
| 73 AstKind; |
| 74 |
| 75 import '../errors.dart' show |
| 76 InputError, |
| 77 internalError, |
| 78 reportCrash, |
| 79 resetCrashReporting; |
| 80 |
| 81 import 'kernel_builder.dart' show |
| 82 Builder, |
| 83 ClassBuilder, |
| 84 DynamicTypeBuilder, |
| 85 InterfaceTypeBuilder, |
| 86 InvalidTypeBuilder, |
| 87 KernelClassBuilder, |
| 88 KernelInterfaceTypeBuilder, |
| 89 KernelLibraryBuilder, |
| 90 KernelProcedureBuilder, |
| 91 LibraryBuilder, |
| 92 MixinApplicationBuilder, |
| 93 NamedMixinApplicationBuilder, |
| 94 TypeBuilder; |
| 95 |
| 96 class KernelSourceTarget extends TargetImplementation { |
| 97 final DillTarget dillTarget; |
| 98 SourceLoader<Library> loader; |
| 99 Program program; |
| 100 |
| 101 final List errors = []; |
| 102 |
| 103 KernelSourceTarget(DillTarget dillTarget, TranslateUri uriTranslator) |
| 104 : dillTarget = dillTarget, |
| 105 super(dillTarget.ticker, uriTranslator) { |
| 106 resetCrashReporting(); |
| 107 loader = new SourceLoader<Library>(this); |
| 108 } |
| 109 |
| 110 void read(Uri uri) { |
| 111 loader.read(uri); |
| 112 } |
| 113 |
| 114 LibraryBuilder createLibraryBuilder(Uri uri) { |
| 115 if (dillTarget.isLoaded) { |
| 116 var builder = dillTarget.loader.builders[uri]; |
| 117 if (builder != null) { |
| 118 return builder; |
| 119 } |
| 120 } |
| 121 return new KernelLibraryBuilder(uri, loader); |
| 122 } |
| 123 |
| 124 void addDirectSupertype(ClassBuilder cls, Set<ClassBuilder> set) { |
| 125 if (cls == null) return; |
| 126 TypeBuilder supertype = cls.supertype; |
| 127 add(InterfaceTypeBuilder type) { |
| 128 Builder builder = type.builder; |
| 129 if (builder is ClassBuilder) { |
| 130 set.add(builder); |
| 131 } else if (builder is! InvalidTypeBuilder && |
| 132 builder is! DynamicTypeBuilder) { |
| 133 internalError("Unhandled: ${builder.runtimeType}"); |
| 134 } |
| 135 } |
| 136 if (supertype == null) { |
| 137 // OK. |
| 138 } else if (supertype is MixinApplicationBuilder) { |
| 139 add(supertype.supertype); |
| 140 for (InterfaceTypeBuilder t in supertype.mixins) { |
| 141 add(t); |
| 142 } |
| 143 } else if (supertype is InterfaceTypeBuilder) { |
| 144 add(supertype); |
| 145 } else { |
| 146 internalError("Unhandled: ${supertype.runtimeType}"); |
| 147 } |
| 148 if (cls.interfaces != null) { |
| 149 for (InterfaceTypeBuilder t in cls.interfaces) { |
| 150 add(t); |
| 151 } |
| 152 } |
| 153 } |
| 154 |
| 155 List<ClassBuilder> collectAllClasses() { |
| 156 List<ClassBuilder> result = <ClassBuilder>[]; |
| 157 loader.builders.forEach((Uri uri, LibraryBuilder library) { |
| 158 library.members.forEach((String name, Builder member) { |
| 159 if (member is KernelClassBuilder) { |
| 160 result.add(member); |
| 161 } |
| 162 }); |
| 163 // TODO(ahe): Translate this if needed: |
| 164 // if (library is KernelLibraryBuilder) { |
| 165 // result.addAll(library.mixinApplicationClasses); |
| 166 // } |
| 167 }); |
| 168 return result; |
| 169 } |
| 170 |
| 171 List<SourceClassBuilder> collectAllSourceClasses() { |
| 172 List<SourceClassBuilder> result = <SourceClassBuilder>[]; |
| 173 loader.builders.forEach((Uri uri, LibraryBuilder library) { |
| 174 library.members.forEach((String name, Builder member) { |
| 175 if (member is SourceClassBuilder) { |
| 176 result.add(member); |
| 177 } |
| 178 }); |
| 179 }); |
| 180 return result; |
| 181 } |
| 182 |
| 183 List<Class> collectAllMixinApplications() { |
| 184 List<Class> result = <Class>[]; |
| 185 loader.builders.forEach((Uri uri, LibraryBuilder library) { |
| 186 if (library is KernelLibraryBuilder) { |
| 187 result.addAll(library.mixinApplicationClasses); |
| 188 } |
| 189 }); |
| 190 return result; |
| 191 } |
| 192 |
| 193 void breakCycle(ClassBuilder builder) { |
| 194 Class cls = builder.target; |
| 195 cls.implementedTypes.clear(); |
| 196 cls.supertype = null; |
| 197 cls.mixedInType = null; |
| 198 builder.supertype = new KernelInterfaceTypeBuilder("Object", null) |
| 199 ..builder = objectClassBuilder; |
| 200 builder.interfaces = null; |
| 201 } |
| 202 |
| 203 Future<Program> handleInputError(Uri uri, InputError error, |
| 204 {bool isFullProgram}) { |
| 205 if (error != null) { |
| 206 String message = error.format(); |
| 207 print(message); |
| 208 errors.add(message); |
| 209 } |
| 210 program = erroneousProgram(); |
| 211 return uri == null |
| 212 ? new Future<Program>.value(program) |
| 213 : writeLinkedProgram(uri, program, isFullProgram: isFullProgram); |
| 214 } |
| 215 |
| 216 Future<Program> writeProgram(Uri uri, AstKind astKind) async { |
| 217 if (loader.first == null) return null; |
| 218 if (errors.isNotEmpty) { |
| 219 return handleInputError(uri, null, isFullProgram: true); |
| 220 } |
| 221 try { |
| 222 if (astKind == AstKind.Analyzer) { |
| 223 loader.buildElementStore(); |
| 224 } else { |
| 225 loader.computeHierarchy(program); |
| 226 } |
| 227 await loader.buildBodies(astKind); |
| 228 loader.finishStaticInvocations(); |
| 229 finishAllConstructors(); |
| 230 transformMixinApplications(); |
| 231 errors.addAll(loader.collectCompileTimeErrors().map((e) => e.format())); |
| 232 if (errors.isNotEmpty) { |
| 233 return handleInputError(uri, null, isFullProgram: true); |
| 234 } |
| 235 if (uri == null) return program; |
| 236 return await writeLinkedProgram(uri, program, isFullProgram: true); |
| 237 } on InputError catch (e) { |
| 238 return handleInputError(uri, e, isFullProgram: true); |
| 239 } catch (e, s) { |
| 240 return reportCrash(e, s, loader?.currentUriForCrashReporting); |
| 241 } |
| 242 } |
| 243 |
| 244 Future<Program> writeOutline(Uri uri) async { |
| 245 if (loader.first == null) return null; |
| 246 try { |
| 247 await loader.buildOutlines(); |
| 248 loader.resolveParts(); |
| 249 loader.computeLibraryScopes(); |
| 250 loader.resolveTypes(); |
| 251 loader.convertConstructors(); |
| 252 loader.buildProgram(); |
| 253 loader.checkSemantics(); |
| 254 List<SourceClassBuilder> sourceClasses = collectAllSourceClasses(); |
| 255 installDefaultSupertypes(sourceClasses); |
| 256 installDefaultConstructors(sourceClasses); |
| 257 loader.resolveConstructors(); |
| 258 program = link(new List<Library>.from(loader.libraries)); |
| 259 if (uri == null) return program; |
| 260 return await writeLinkedProgram(uri, program, isFullProgram: false); |
| 261 } on InputError catch (e) { |
| 262 return handleInputError(uri, e, isFullProgram: false); |
| 263 } catch (e, s) { |
| 264 return reportCrash(e, s, loader?.currentUriForCrashReporting); |
| 265 } |
| 266 } |
| 267 |
| 268 Program erroneousProgram() { |
| 269 Uri uri = loader.first?.uri ?? Uri.parse("error:error"); |
| 270 KernelLibraryBuilder library = new KernelLibraryBuilder(uri, loader); |
| 271 KernelProcedureBuilder mainBuilder = new KernelProcedureBuilder(null, 0, |
| 272 null, "main", null, null, AsyncMarker.Sync, ProcedureKind.Method); |
| 273 library.addBuilder(mainBuilder.name, mainBuilder); |
| 274 loader.first = library; |
| 275 mainBuilder.body = new ExpressionStatement( |
| 276 new Throw(new StringLiteral("${errors.join('\n')}"))); |
| 277 library.build(); |
| 278 return link(<Library>[library.library]); |
| 279 } |
| 280 |
| 281 /// Creates a program by combining [libraries] with the libraries of |
| 282 /// `dillTarget.loader.program`. |
| 283 Program link(List<Library> libraries) { |
| 284 Map<String, List<int>> uriToLineStarts = <String, List<int>>{}; |
| 285 |
| 286 // for (Library library in libraries) { |
| 287 // // TODO(ahe): Compute line starts instead. |
| 288 // uriToLineStarts[library.fileUri] = <int>[0]; |
| 289 // } |
| 290 |
| 291 final Program binary = dillTarget.loader.program; |
| 292 if (binary != null) { |
| 293 libraries.addAll(binary.libraries); |
| 294 uriToLineStarts.addAll(binary.uriToLineStarts); |
| 295 } |
| 296 |
| 297 // TODO(ahe): Remove this line. Kernel seems to generate a default line map |
| 298 // that used when there's no fileUri on an element. Instead, ensure all |
| 299 // elements have a fileUri. |
| 300 uriToLineStarts[""] = <int>[0]; |
| 301 Program program = new Program(libraries, uriToLineStarts); |
| 302 if (loader.first != null) { |
| 303 Builder builder = loader.first.members["main"]; |
| 304 if (builder is KernelProcedureBuilder) { |
| 305 program.mainMethod = builder.procedure; |
| 306 } |
| 307 } |
| 308 // TODO(ahe): This is kinda hackish. Use the transformer instead. |
| 309 LibraryBuilder builtin = |
| 310 dillTarget.loader.builders[Uri.parse("dart:_builtin")]; |
| 311 if (builtin != null) { |
| 312 DillMemberBuilder builder = builtin.members["_getMainClosure"]; |
| 313 if (builder != null) { |
| 314 Expression getMain = program.mainMethod == null |
| 315 ? new Throw(new StringLiteral("No main method.")) |
| 316 : new StaticGet(program.mainMethod); |
| 317 Procedure procedure = builder.member; |
| 318 procedure.function = new FunctionNode(new ReturnStatement(getMain)); |
| 319 procedure.function.parent = procedure; |
| 320 } |
| 321 } |
| 322 ticker.logMs("Linked program"); |
| 323 return program; |
| 324 } |
| 325 |
| 326 Future<Program> writeLinkedProgram(Uri uri, Program program, |
| 327 {bool isFullProgram}) async { |
| 328 File output = new File.fromUri(uri); |
| 329 IOSink sink = output.openWrite(); |
| 330 try { |
| 331 new BinaryPrinter(sink).writeProgramFile(program); |
| 332 } finally { |
| 333 await sink.close(); |
| 334 } |
| 335 if (isFullProgram) { |
| 336 ticker.logMs("Wrote program to ${uri.toFilePath()}"); |
| 337 } else { |
| 338 ticker.logMs("Wrote outline to ${uri.toFilePath()}"); |
| 339 } |
| 340 return null; |
| 341 } |
| 342 |
| 343 void installDefaultSupertypes(List<SourceClassBuilder> builders) { |
| 344 Class objectClass = this.objectClass; |
| 345 for (SourceClassBuilder builder in builders) { |
| 346 Class cls = builder.target; |
| 347 if (cls != objectClass) { |
| 348 cls.supertype ??= objectClass.asRawSupertype; |
| 349 } |
| 350 } |
| 351 ticker.logMs("Installed Object as implicit superclass"); |
| 352 } |
| 353 |
| 354 void installDefaultConstructors(List<SourceClassBuilder> builders) { |
| 355 Class objectClass = this.objectClass; |
| 356 for (SourceClassBuilder builder in builders) { |
| 357 if (builder.target != objectClass) { |
| 358 installDefaultConstructor(builder); |
| 359 } |
| 360 } |
| 361 ticker.logMs("Installed default constructors"); |
| 362 } |
| 363 |
| 364 KernelClassBuilder get objectClassBuilder { |
| 365 return loader.coreLibrary.exports["Object"]; |
| 366 } |
| 367 |
| 368 Class get objectClass => objectClassBuilder.cls; |
| 369 |
| 370 /// If [builder] doesn't have a constructors, install the defaults. |
| 371 void installDefaultConstructor(SourceClassBuilder builder) { |
| 372 if (!builder.constructors.isEmpty) return; |
| 373 /// Quotes below are from [Dart Programming Language Specification, 4th |
| 374 /// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/EC
MA-408.pdf): |
| 375 if (builder is NamedMixinApplicationBuilder) { |
| 376 /// >A mixin application of the form S with M; defines a class C with |
| 377 /// >superclass S. |
| 378 /// >... |
| 379 |
| 380 /// >Let LM be the library in which M is declared. For each generative |
| 381 /// >constructor named qi(Ti1 ai1, . . . , Tiki aiki), i in 1..n of S |
| 382 /// >that is accessible to LM , C has an implicitly declared constructor |
| 383 /// >named q'i = [C/S]qi of the form q'i(ai1,...,aiki) : |
| 384 /// >super(ai1,...,aiki);. |
| 385 Builder supertype = builder; |
| 386 while (supertype is NamedMixinApplicationBuilder) { |
| 387 NamedMixinApplicationBuilder named = supertype; |
| 388 TypeBuilder type = named.mixinApplication; |
| 389 if (type is MixinApplicationBuilder) { |
| 390 MixinApplicationBuilder t = type; |
| 391 type = t.supertype; |
| 392 } |
| 393 if (type is InterfaceTypeBuilder) { |
| 394 supertype = type.builder; |
| 395 } else { |
| 396 internalError("Unhandled: ${type.runtimeType}"); |
| 397 } |
| 398 } |
| 399 if (supertype is KernelClassBuilder) { |
| 400 for (Constructor constructor in supertype.cls.constructors) { |
| 401 builder.addSyntheticConstructor( |
| 402 makeMixinApplicationConstructor(builder.cls.mixin, constructor)); |
| 403 } |
| 404 } else { |
| 405 internalError("Unhandled: ${supertype.runtimeType}"); |
| 406 } |
| 407 } else { |
| 408 /// >Iff no constructor is specified for a class C, it implicitly has a |
| 409 /// >default constructor C() : super() {}, unless C is class Object. |
| 410 // The superinitializer is installed below in [finishConstructors]. |
| 411 builder.addSyntheticConstructor(makeDefaultConstructor()); |
| 412 } |
| 413 } |
| 414 |
| 415 Constructor makeMixinApplicationConstructor( |
| 416 Class mixin, Constructor constructor) { |
| 417 VariableDeclaration copyFormal(VariableDeclaration formal) { |
| 418 // TODO(ahe): Handle initializers. |
| 419 return new VariableDeclaration(formal.name, |
| 420 type: formal.type, isFinal: formal.isFinal, isConst: formal.isConst); |
| 421 } |
| 422 List<VariableDeclaration> positionalParameters = <VariableDeclaration>[]; |
| 423 List<VariableDeclaration> namedParameters = <VariableDeclaration>[]; |
| 424 List<Expression> positional = <Expression>[]; |
| 425 List<NamedExpression> named = <NamedExpression>[]; |
| 426 for (VariableDeclaration formal in |
| 427 constructor.function.positionalParameters) { |
| 428 positionalParameters.add(copyFormal(formal)); |
| 429 positional.add(new VariableGet(positionalParameters.last)); |
| 430 } |
| 431 for (VariableDeclaration formal in |
| 432 constructor.function.namedParameters) { |
| 433 namedParameters.add(copyFormal(formal)); |
| 434 named.add(new NamedExpression( |
| 435 formal.name, new VariableGet(namedParameters.last))); |
| 436 } |
| 437 FunctionNode function = new FunctionNode(new EmptyStatement(), |
| 438 positionalParameters: positionalParameters, |
| 439 namedParameters: namedParameters, |
| 440 requiredParameterCount: constructor.function.requiredParameterCount, |
| 441 returnType: const VoidType()); |
| 442 SuperInitializer initializer = new SuperInitializer( |
| 443 constructor, new Arguments(positional, named: named)); |
| 444 return new Constructor(function, |
| 445 name: constructor.name, |
| 446 initializers: <Initializer>[initializer]); |
| 447 } |
| 448 |
| 449 Constructor makeDefaultConstructor() { |
| 450 return new Constructor( |
| 451 new FunctionNode(new EmptyStatement(), returnType: const VoidType()), |
| 452 name: new Name("")); |
| 453 } |
| 454 |
| 455 void finishAllConstructors() { |
| 456 Class objectClass = this.objectClass; |
| 457 for (SourceClassBuilder builder in collectAllSourceClasses()) { |
| 458 Class cls = builder.target; |
| 459 if (cls != objectClass) { |
| 460 finishConstructors(cls); |
| 461 } |
| 462 } |
| 463 ticker.logMs("Finished constructors"); |
| 464 } |
| 465 |
| 466 /// Ensure constructors of [cls] have the correct initializers and other |
| 467 /// requirements. |
| 468 void finishConstructors(Class cls) { |
| 469 /// Quotes below are from [Dart Programming Language Specification, 4th |
| 470 /// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/EC
MA-408.pdf): |
| 471 Constructor superTarget; |
| 472 List<Field> uninitializedFields = <Field>[]; |
| 473 for (Field field in cls.fields) { |
| 474 if (field.initializer == null) { |
| 475 uninitializedFields.add(field); |
| 476 } |
| 477 } |
| 478 Map<Constructor, List<FieldInitializer>> fieldInitializers = |
| 479 <Constructor, List<FieldInitializer>>{}; |
| 480 for (Constructor constructor in cls.constructors) { |
| 481 if (!isRedirectingGenerativeConstructor(constructor)) { |
| 482 /// >If no superinitializer is provided, an implicit superinitializer |
| 483 /// >of the form super() is added at the end of k’s initializer list, |
| 484 /// >unless the enclosing class is class Object. |
| 485 if (!constructor.initializers.any(isSuperinitializerOrInvalid)) { |
| 486 superTarget ??= defaultSuperConstructor(cls); |
| 487 Initializer initializer; |
| 488 if (superTarget == null) { |
| 489 initializer = new InvalidInitializer(); |
| 490 } else { |
| 491 initializer = |
| 492 new SuperInitializer(superTarget, new Arguments.empty()); |
| 493 } |
| 494 constructor.initializers.add(initializer); |
| 495 initializer.parent = constructor; |
| 496 } |
| 497 if (constructor.function.body == null) { |
| 498 /// >If a generative constructor c is not a redirecting constructor |
| 499 /// >and no body is provided, then c implicitly has an empty body {}. |
| 500 /// We use an empty statement instead. |
| 501 constructor.function.body = new EmptyStatement(); |
| 502 constructor.function.body.parent = constructor.function; |
| 503 } |
| 504 List<FieldInitializer> myFieldInitializers = <FieldInitializer>[]; |
| 505 for (Initializer initializer in constructor.initializers) { |
| 506 if (initializer is FieldInitializer) { |
| 507 myFieldInitializers.add(initializer); |
| 508 } |
| 509 } |
| 510 fieldInitializers[constructor] = myFieldInitializers; |
| 511 } |
| 512 } |
| 513 Set<Field> initializedFields; |
| 514 fieldInitializers.forEach( |
| 515 (Constructor constructor, List<FieldInitializer> initializers) { |
| 516 Iterable<Field> fields = initializers.map((i) => i.field); |
| 517 if (initializedFields == null) { |
| 518 initializedFields = new Set<Field>.from(fields); |
| 519 } else { |
| 520 initializedFields.addAll(fields); |
| 521 } |
| 522 }); |
| 523 // Run through all fields that aren't initialized by any constructor, and |
| 524 // set their initializer to `null`. |
| 525 for (Field field in uninitializedFields) { |
| 526 if (initializedFields == null || !initializedFields.contains(field)) { |
| 527 field.initializer = new NullLiteral() |
| 528 ..parent = field; |
| 529 } |
| 530 } |
| 531 // Run through all fields that are initialized by some constructor, and |
| 532 // make sure that all other constructors also initialize them. |
| 533 fieldInitializers.forEach( |
| 534 (Constructor constructor, List<FieldInitializer> initializers) { |
| 535 Iterable<Field> fields = initializers.map((i) => i.field); |
| 536 for (Field field in initializedFields.difference(fields.toSet())) { |
| 537 if (field.initializer == null) { |
| 538 FieldInitializer initializer = |
| 539 new FieldInitializer(field, new NullLiteral()); |
| 540 initializer.parent = constructor; |
| 541 constructor.initializers.insert(0, initializer); |
| 542 } |
| 543 } |
| 544 }); |
| 545 } |
| 546 |
| 547 void transformMixinApplications() { |
| 548 new MixinFullResolution().transform(program); |
| 549 ticker.logMs("Transformed mixin applications"); |
| 550 } |
| 551 |
| 552 void dumpIr() { |
| 553 StringBuffer sb = new StringBuffer(); |
| 554 for (Library library in loader.libraries) { |
| 555 Printer printer = new Printer(sb); |
| 556 printer.writeLibraryFile(library); |
| 557 } |
| 558 print("$sb"); |
| 559 } |
| 560 } |
| 561 |
| 562 bool isSuperinitializerOrInvalid(Initializer initializer) { |
| 563 return initializer is SuperInitializer |
| 564 || initializer is InvalidInitializer; |
| 565 } |
| 566 |
| 567 bool isRedirectingGenerativeConstructor(Constructor constructor) { |
| 568 List<Initializer> initializers = constructor.initializers; |
| 569 return initializers.length == 1 |
| 570 && initializers.single is RedirectingInitializer; |
| 571 } |
| 572 |
| 573 /// Looks for a constructor call that matches `super()` from a constructor in |
| 574 /// [cls]. Such a constructor may have optional arguments, but no required |
| 575 /// arguments. |
| 576 Constructor defaultSuperConstructor(Class cls) { |
| 577 Class superclass = cls.superclass; |
| 578 while (superclass != null && superclass.isMixinApplication) { |
| 579 superclass = superclass.superclass; |
| 580 } |
| 581 for (Constructor constructor in superclass.constructors) { |
| 582 if (constructor.name.name.isEmpty) { |
| 583 return constructor.function.requiredParameterCount == 0 ? |
| 584 constructor : null; |
| 585 } |
| 586 } |
| 587 return null; |
| 588 } |
| OLD | NEW |