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

Side by Side Diff: pkg/front_end/lib/src/fasta/kernel/kernel_target.dart

Issue 2800083002: Complain about incorrect this/super constructor initializers. (Closed)
Patch Set: Created 3 years, 8 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
OLDNEW
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, IOSink; 9 import 'dart:io' show File, IOSink;
10 10
(...skipping 12 matching lines...) Expand all
23 FieldInitializer, 23 FieldInitializer,
24 FunctionNode, 24 FunctionNode,
25 Initializer, 25 Initializer,
26 InvalidInitializer, 26 InvalidInitializer,
27 Library, 27 Library,
28 Name, 28 Name,
29 NamedExpression, 29 NamedExpression,
30 NullLiteral, 30 NullLiteral,
31 ProcedureKind, 31 ProcedureKind,
32 Program, 32 Program,
33 RedirectingInitializer,
34 Source, 33 Source,
35 StringLiteral, 34 StringLiteral,
36 SuperInitializer, 35 SuperInitializer,
37 Throw, 36 Throw,
38 TypeParameter, 37 TypeParameter,
39 VariableDeclaration, 38 VariableDeclaration,
40 VariableGet, 39 VariableGet,
41 VoidType; 40 VoidType;
42 41
43 import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter; 42 import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 import 'kernel_builder.dart' 75 import 'kernel_builder.dart'
77 show 76 show
78 Builder, 77 Builder,
79 ClassBuilder, 78 ClassBuilder,
80 InvalidTypeBuilder, 79 InvalidTypeBuilder,
81 KernelClassBuilder, 80 KernelClassBuilder,
82 KernelLibraryBuilder, 81 KernelLibraryBuilder,
83 KernelNamedTypeBuilder, 82 KernelNamedTypeBuilder,
84 KernelProcedureBuilder, 83 KernelProcedureBuilder,
85 LibraryBuilder, 84 LibraryBuilder,
85 MemberBuilder,
86 MixinApplicationBuilder, 86 MixinApplicationBuilder,
87 NamedMixinApplicationBuilder, 87 NamedMixinApplicationBuilder,
88 NamedTypeBuilder, 88 NamedTypeBuilder,
89 TypeBuilder, 89 TypeBuilder,
90 TypeVariableBuilder; 90 TypeVariableBuilder;
91 91
92 import 'verifier.dart' show verifyProgram; 92 import 'verifier.dart' show verifyProgram;
93 93
94 class KernelTarget extends TargetImplementation { 94 class KernelTarget extends TargetImplementation {
95 final DillTarget dillTarget; 95 final DillTarget dillTarget;
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 AsyncMarker.Sync, 348 AsyncMarker.Sync,
349 ProcedureKind.Method, 349 ProcedureKind.Method,
350 library, 350 library,
351 -1, 351 -1,
352 -1, 352 -1,
353 -1); 353 -1);
354 library.addBuilder(mainBuilder.name, mainBuilder, -1); 354 library.addBuilder(mainBuilder.name, mainBuilder, -1);
355 mainBuilder.body = new ExpressionStatement( 355 mainBuilder.body = new ExpressionStatement(
356 new Throw(new StringLiteral("${errors.join('\n')}"))); 356 new Throw(new StringLiteral("${errors.join('\n')}")));
357 } 357 }
358 library.build(); 358 library.build(loader.coreLibrary);
359 return link(<Library>[library.library]); 359 return link(<Library>[library.library]);
360 } 360 }
361 361
362 /// Creates a program by combining [libraries] with the libraries of 362 /// Creates a program by combining [libraries] with the libraries of
363 /// `dillTarget.loader.program`. 363 /// `dillTarget.loader.program`.
364 Program link(List<Library> libraries) { 364 Program link(List<Library> libraries) {
365 Map<String, Source> uriToSource = 365 Map<String, Source> uriToSource =
366 new Map<String, Source>.from(this.uriToSource); 366 new Map<String, Source>.from(this.uriToSource);
367 367
368 final Program binary = dillTarget.loader.program; 368 final Program binary = dillTarget.loader.program;
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 return new Constructor( 555 return new Constructor(
556 new FunctionNode(new EmptyStatement(), returnType: const VoidType()), 556 new FunctionNode(new EmptyStatement(), returnType: const VoidType()),
557 name: new Name("")); 557 name: new Name(""));
558 } 558 }
559 559
560 void finishAllConstructors() { 560 void finishAllConstructors() {
561 Class objectClass = this.objectClass; 561 Class objectClass = this.objectClass;
562 for (SourceClassBuilder builder in collectAllSourceClasses()) { 562 for (SourceClassBuilder builder in collectAllSourceClasses()) {
563 Class cls = builder.target; 563 Class cls = builder.target;
564 if (cls != objectClass) { 564 if (cls != objectClass) {
565 finishConstructors(cls); 565 finishConstructors(builder);
566 } 566 }
567 } 567 }
568 ticker.logMs("Finished constructors"); 568 ticker.logMs("Finished constructors");
569 } 569 }
570 570
571 /// Ensure constructors of [cls] have the correct initializers and other 571 /// Ensure constructors of [cls] have the correct initializers and other
572 /// requirements. 572 /// requirements.
573 void finishConstructors(Class cls) { 573 void finishConstructors(SourceClassBuilder builder) {
574 Class cls = builder.target;
575
574 /// Quotes below are from [Dart Programming Language Specification, 4th 576 /// Quotes below are from [Dart Programming Language Specification, 4th
575 /// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/EC MA-408.pdf): 577 /// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/EC MA-408.pdf):
576 Constructor superTarget;
577 List<Field> uninitializedFields = <Field>[]; 578 List<Field> uninitializedFields = <Field>[];
578 List<Field> nonFinalFields = <Field>[]; 579 List<Field> nonFinalFields = <Field>[];
579 for (Field field in cls.fields) { 580 for (Field field in cls.fields) {
580 if (field.isInstanceMember && !field.isFinal) { 581 if (field.isInstanceMember && !field.isFinal) {
581 nonFinalFields.add(field); 582 nonFinalFields.add(field);
582 } 583 }
583 if (field.initializer == null) { 584 if (field.initializer == null) {
584 uninitializedFields.add(field); 585 uninitializedFields.add(field);
585 } 586 }
586 } 587 }
587 Map<Constructor, List<FieldInitializer>> fieldInitializers = 588 Map<Constructor, List<FieldInitializer>> fieldInitializers =
588 <Constructor, List<FieldInitializer>>{}; 589 <Constructor, List<FieldInitializer>>{};
589 for (Constructor constructor in cls.constructors) { 590 Constructor superTarget;
590 if (!isRedirectingGenerativeConstructor(constructor)) { 591 builder.constructors.forEach((String name, Builder member) {
592 if (member.isFactory) return;
593 MemberBuilder constructorBuilder = member;
594 Constructor constructor = constructorBuilder.target;
595 if (!constructorBuilder.isRedirectingGenerativeConstructor) {
591 /// >If no superinitializer is provided, an implicit superinitializer 596 /// >If no superinitializer is provided, an implicit superinitializer
592 /// >of the form super() is added at the end of k’s initializer list, 597 /// >of the form super() is added at the end of k’s initializer list,
593 /// >unless the enclosing class is class Object. 598 /// >unless the enclosing class is class Object.
594 if (!constructor.initializers.any(isSuperinitializerOrInvalid)) { 599 if (constructor.initializers.isEmpty) {
595 superTarget ??= defaultSuperConstructor(cls); 600 superTarget ??= defaultSuperConstructor(cls);
596 Initializer initializer; 601 Initializer initializer;
597 if (superTarget == null) { 602 if (superTarget == null) {
598 addError( 603 addError(
599 constructor.enclosingClass.fileUri, 604 constructor.enclosingClass.fileUri,
600 constructor.fileOffset, 605 constructor.fileOffset,
601 "${cls.superclass.name} has no constructor that takes no" 606 "${cls.superclass.name} has no constructor that takes no"
602 " arguments."); 607 " arguments.");
603 initializer = new InvalidInitializer(); 608 initializer = new InvalidInitializer();
604 } else { 609 } else {
(...skipping 20 matching lines...) Expand all
625 if (constructor.isConst && nonFinalFields.isNotEmpty) { 630 if (constructor.isConst && nonFinalFields.isNotEmpty) {
626 addError(constructor.enclosingClass.fileUri, constructor.fileOffset, 631 addError(constructor.enclosingClass.fileUri, constructor.fileOffset,
627 "Constructor is marked 'const' so all fields must be final."); 632 "Constructor is marked 'const' so all fields must be final.");
628 for (Field field in nonFinalFields) { 633 for (Field field in nonFinalFields) {
629 addError(constructor.enclosingClass.fileUri, field.fileOffset, 634 addError(constructor.enclosingClass.fileUri, field.fileOffset,
630 "Field isn't final, but constructor is 'const'."); 635 "Field isn't final, but constructor is 'const'.");
631 } 636 }
632 nonFinalFields.clear(); 637 nonFinalFields.clear();
633 } 638 }
634 } 639 }
635 } 640 });
636 Set<Field> initializedFields; 641 Set<Field> initializedFields;
637 fieldInitializers.forEach( 642 fieldInitializers.forEach(
638 (Constructor constructor, List<FieldInitializer> initializers) { 643 (Constructor constructor, List<FieldInitializer> initializers) {
639 Iterable<Field> fields = initializers.map((i) => i.field); 644 Iterable<Field> fields = initializers.map((i) => i.field);
640 if (initializedFields == null) { 645 if (initializedFields == null) {
641 initializedFields = new Set<Field>.from(fields); 646 initializedFields = new Set<Field>.from(fields);
642 } else { 647 } else {
643 initializedFields.addAll(fields); 648 initializedFields.addAll(fields);
644 } 649 }
645 }); 650 });
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
689 print("$sb"); 694 print("$sb");
690 ticker.logMs("Dumped IR"); 695 ticker.logMs("Dumped IR");
691 } 696 }
692 697
693 void verify() { 698 void verify() {
694 errors.addAll(verifyProgram(program)); 699 errors.addAll(verifyProgram(program));
695 ticker.logMs("Verified program"); 700 ticker.logMs("Verified program");
696 } 701 }
697 } 702 }
698 703
699 bool isSuperinitializerOrInvalid(Initializer initializer) {
700 return initializer is SuperInitializer || initializer is InvalidInitializer;
701 }
702
703 bool isRedirectingGenerativeConstructor(Constructor constructor) {
704 List<Initializer> initializers = constructor.initializers;
705 return initializers.length == 1 &&
706 initializers.single is RedirectingInitializer;
707 }
708
709 /// Looks for a constructor call that matches `super()` from a constructor in 704 /// Looks for a constructor call that matches `super()` from a constructor in
710 /// [cls]. Such a constructor may have optional arguments, but no required 705 /// [cls]. Such a constructor may have optional arguments, but no required
711 /// arguments. 706 /// arguments.
712 Constructor defaultSuperConstructor(Class cls) { 707 Constructor defaultSuperConstructor(Class cls) {
713 Class superclass = cls.superclass; 708 Class superclass = cls.superclass;
714 while (superclass != null && superclass.isMixinApplication) { 709 while (superclass != null && superclass.isMixinApplication) {
715 superclass = superclass.superclass; 710 superclass = superclass.superclass;
716 } 711 }
717 for (Constructor constructor in superclass.constructors) { 712 for (Constructor constructor in superclass.constructors) {
718 if (constructor.name.name.isEmpty) { 713 if (constructor.name.name.isEmpty) {
719 return constructor.function.requiredParameterCount == 0 714 return constructor.function.requiredParameterCount == 0
720 ? constructor 715 ? constructor
721 : null; 716 : null;
722 } 717 }
723 } 718 }
724 return null; 719 return null;
725 } 720 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698