| // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| library fasta.source_class_builder; |
| |
| import 'package:front_end/src/fasta/builder/class_builder.dart' |
| show ClassBuilder; |
| |
| import 'package:front_end/src/fasta/type_inference/type_inferrer.dart' |
| show TypeInferrer; |
| |
| import 'package:kernel/ast.dart' |
| show Class, Constructor, Supertype, TreeNode, setParents; |
| |
| import '../errors.dart' show internalError; |
| |
| import '../kernel/kernel_builder.dart' |
| show |
| Builder, |
| ConstructorReferenceBuilder, |
| KernelClassBuilder, |
| KernelFieldBuilder, |
| KernelFunctionBuilder, |
| KernelLibraryBuilder, |
| KernelTypeBuilder, |
| KernelTypeVariableBuilder, |
| LibraryBuilder, |
| MetadataBuilder, |
| Scope, |
| TypeVariableBuilder, |
| compareProcedures; |
| |
| import '../dill/dill_member_builder.dart' show DillMemberBuilder; |
| |
| import '../util/relativize.dart' show relativizeUri; |
| |
| Class initializeClass( |
| Class cls, String name, LibraryBuilder parent, int charOffset) { |
| cls ??= new Class(name: name); |
| cls.fileUri ??= relativizeUri(parent.fileUri); |
| if (cls.fileOffset == TreeNode.noOffset) { |
| cls.fileOffset = charOffset; |
| } |
| return cls; |
| } |
| |
| class SourceClassBuilder extends KernelClassBuilder { |
| final Class cls; |
| |
| final List<ConstructorReferenceBuilder> constructorReferences; |
| |
| final KernelTypeBuilder mixedInType; |
| |
| SourceClassBuilder( |
| List<MetadataBuilder> metadata, |
| int modifiers, |
| String name, |
| List<TypeVariableBuilder> typeVariables, |
| KernelTypeBuilder supertype, |
| List<KernelTypeBuilder> interfaces, |
| Scope scope, |
| Scope constructors, |
| LibraryBuilder parent, |
| this.constructorReferences, |
| int charOffset, |
| [Class cls, |
| this.mixedInType]) |
| : cls = initializeClass(cls, name, parent, charOffset), |
| super(metadata, modifiers, name, typeVariables, supertype, interfaces, |
| scope, constructors, parent, charOffset); |
| |
| int resolveTypes(LibraryBuilder library) { |
| int count = 0; |
| if (typeVariables != null) { |
| for (KernelTypeVariableBuilder t in typeVariables) { |
| cls.typeParameters.add(t.parameter); |
| } |
| setParents(cls.typeParameters, cls); |
| count += cls.typeParameters.length; |
| } |
| return count + super.resolveTypes(library); |
| } |
| |
| Class build(KernelLibraryBuilder library, LibraryBuilder coreLibrary) { |
| void buildBuilders(String name, Builder builder) { |
| do { |
| if (builder is KernelFieldBuilder) { |
| // TODO(ahe): It would be nice to have a common interface for the |
| // build method to avoid duplicating these two cases. |
| cls.addMember(builder.build(library)); |
| } else if (builder is KernelFunctionBuilder) { |
| cls.addMember(builder.build(library)); |
| } else { |
| internalError("Unhandled builder: ${builder.runtimeType}"); |
| } |
| builder = builder.next; |
| } while (builder != null); |
| } |
| |
| scope.forEach(buildBuilders); |
| constructors.forEach(buildBuilders); |
| cls.supertype = supertype?.buildSupertype(library); |
| cls.mixedInType = mixedInType?.buildSupertype(library); |
| // TODO(ahe): If `cls.supertype` is null, and this isn't Object, report a |
| // compile-time error. |
| cls.isAbstract = isAbstract; |
| if (interfaces != null) { |
| for (KernelTypeBuilder interface in interfaces) { |
| Supertype supertype = interface.buildSupertype(library); |
| if (supertype != null) { |
| // TODO(ahe): Report an error if supertype is null. |
| cls.implementedTypes.add(supertype); |
| } |
| } |
| } |
| |
| constructors.forEach((String name, Builder constructor) { |
| Builder member = scopeBuilder[name]; |
| if (member == null) return; |
| // TODO(ahe): charOffset is missing. |
| addCompileTimeError( |
| constructor.charOffset, "Conflicts with member '${name}'."); |
| if (constructor.isFactory) { |
| addCompileTimeError(member.charOffset, |
| "Conflicts with factory '${this.name}.${name}'."); |
| } else { |
| addCompileTimeError(member.charOffset, |
| "Conflicts with constructor '${this.name}.${name}'."); |
| } |
| }); |
| |
| scope.setters.forEach((String name, Builder setter) { |
| Builder member = scopeBuilder[name]; |
| if (member == null || !member.isField || member.isFinal) return; |
| // TODO(ahe): charOffset is missing. |
| var report = member.isInstanceMember != setter.isInstanceMember |
| ? addWarning |
| : addCompileTimeError; |
| report(setter.charOffset, "Conflicts with member '${name}'."); |
| report(member.charOffset, "Conflicts with setter '${name}'."); |
| }); |
| |
| cls.procedures.sort(compareProcedures); |
| return cls; |
| } |
| |
| void addSyntheticConstructor(Constructor constructor) { |
| String name = constructor.name.name; |
| cls.constructors.add(constructor); |
| constructor.parent = cls; |
| DillMemberBuilder memberBuilder = new DillMemberBuilder(constructor, this); |
| memberBuilder.next = constructorScopeBuilder[name]; |
| constructorScopeBuilder.addMember(name, memberBuilder); |
| } |
| |
| @override |
| void prepareInitializerInference(TypeInferrer typeInferrer, |
| LibraryBuilder library, ClassBuilder currentClass) { |
| scope.forEach((name, builder) { |
| builder.prepareInitializerInference(typeInferrer, library, this); |
| }); |
| } |
| } |