Index: pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart |
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart |
index d7598fd056935e29db2a8ea7d4acfe8a774c18ce..45b17e597b90736e39df436e4336873dd2b672b3 100644 |
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart |
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart |
@@ -46,10 +46,10 @@ import 'kernel_builder.dart' |
KernelTypeVariableBuilder, |
MemberBuilder, |
MetadataBuilder, |
- MixedAccessor, |
NamedMixinApplicationBuilder, |
PrefixBuilder, |
ProcedureBuilder, |
+ Scope, |
TypeBuilder, |
TypeVariableBuilder, |
compareProcedures; |
@@ -103,6 +103,17 @@ class KernelLibraryBuilder |
int charOffset) { |
assert(currentDeclaration.parent == libraryDeclaration); |
Map<String, MemberBuilder> members = currentDeclaration.members; |
+ Map<String, MemberBuilder> constructors = currentDeclaration.constructors; |
+ Map<String, MemberBuilder> setters = currentDeclaration.setters; |
+ |
+ Scope classScope = new Scope( |
+ members, setters, scope.withTypeVariables(typeVariables), |
+ isModifiable: false); |
+ |
+ // When looking up a constructor, we don't consider type variables or the |
+ // library scope. |
+ Scope constructorScope = |
+ new Scope(constructors, null, null, isModifiable: false); |
ClassBuilder cls = new SourceClassBuilder( |
metadata, |
modifiers, |
@@ -110,17 +121,22 @@ class KernelLibraryBuilder |
typeVariables, |
supertype, |
interfaces, |
- members, |
+ classScope, |
+ constructorScope, |
this, |
new List<ConstructorReferenceBuilder>.from(constructorReferences), |
charOffset); |
constructorReferences.clear(); |
- members.forEach((String name, MemberBuilder builder) { |
- while (builder != null) { |
- builder.parent = cls; |
- builder = builder.next; |
+ void setParent(String name, MemberBuilder member) { |
+ while (member != null) { |
+ member.parent = cls; |
+ member = member.next; |
} |
- }); |
+ } |
+ |
+ members.forEach(setParent); |
+ constructors.forEach(setParent); |
+ setters.forEach(setParent); |
// Nested declaration began in `OutlineBuilder.beginClassDeclaration`. |
endNestedDeclaration().resolveTypes(typeVariables, this); |
addBuilder(className, cls, charOffset); |
@@ -151,10 +167,28 @@ class KernelLibraryBuilder |
charOffset); |
} |
- String computeConstructorName(String name) { |
- assert(isConstructorName(name, currentDeclaration.name)); |
+ String computeAndValidateConstructorName(String name, int charOffset) { |
+ String className = currentDeclaration.name; |
+ bool startsWithClassName = name.startsWith(className); |
+ if (startsWithClassName && name.length == className.length) { |
+ // Unnamed constructor or factory. |
+ return ""; |
+ } |
int index = name.indexOf("."); |
- return index == -1 ? "" : name.substring(index + 1); |
+ if (startsWithClassName && index == className.length) { |
+ // Named constructor or factory. |
+ return name.substring(index + 1); |
+ } |
+ if (index == -1) { |
+ // A legal name for a regular method, but not for a constructor. |
+ return null; |
+ } |
+ String suffix = name.substring(index + 1); |
+ addCompileTimeError( |
+ charOffset, |
+ "'$name' isn't a legal method name.\n" |
+ "Did you mean '$className.$suffix'?"); |
+ return suffix; |
} |
void addProcedure( |
@@ -175,8 +209,10 @@ class KernelLibraryBuilder |
// `OutlineBuilder.beginTopLevelMethod`. |
endNestedDeclaration().resolveTypes(typeVariables, this); |
ProcedureBuilder procedure; |
- if (!isTopLevel && isConstructorName(name, currentDeclaration.name)) { |
- name = computeConstructorName(name); |
+ String constructorName = |
+ isTopLevel ? null : computeAndValidateConstructorName(name, charOffset); |
+ if (constructorName != null) { |
+ name = constructorName; |
procedure = new KernelConstructorBuilder( |
metadata, |
modifiers & ~abstractMask, |
@@ -214,7 +250,7 @@ class KernelLibraryBuilder |
void addFactoryMethod( |
List<MetadataBuilder> metadata, |
int modifiers, |
- ConstructorReferenceBuilder constructorName, |
+ ConstructorReferenceBuilder constructorNameReference, |
List<FormalParameterBuilder> formals, |
AsyncMarker asyncModifier, |
ConstructorReferenceBuilder redirectionTarget, |
@@ -225,11 +261,13 @@ class KernelLibraryBuilder |
// Nested declaration began in `OutlineBuilder.beginFactoryMethod`. |
DeclarationBuilder<KernelTypeBuilder> factoryDeclaration = |
endNestedDeclaration(); |
- String name = constructorName.name; |
- if (isConstructorName(name, currentDeclaration.name)) { |
- name = computeConstructorName(name); |
+ String name = constructorNameReference.name; |
+ String constructorName = |
+ computeAndValidateConstructorName(name, charOffset); |
+ if (constructorName != null) { |
+ name = constructorName; |
} |
- assert(constructorName.suffix == null); |
+ assert(constructorNameReference.suffix == null); |
KernelProcedureBuilder procedure = new KernelProcedureBuilder( |
metadata, |
staticMask | modifiers, |
@@ -335,6 +373,7 @@ class KernelLibraryBuilder |
Builder buildAmbiguousBuilder( |
String name, Builder builder, Builder other, int charOffset, |
{bool isExport: false, bool isImport: false}) { |
+ // TODO(ahe): Can I move this to Scope or Prefix? |
if (builder == other) return builder; |
if (builder is InvalidTypeBuilder) return builder; |
if (other is InvalidTypeBuilder) return other; |
@@ -352,7 +391,7 @@ class KernelLibraryBuilder |
Uri otherUri; |
Uri preferredUri; |
Uri hiddenUri; |
- if (members[name] == builder) { |
+ if (scope.local[name] == builder) { |
isLocal = true; |
preferred = builder; |
hiddenUri = other.computeLibraryUri(); |
@@ -394,26 +433,15 @@ class KernelLibraryBuilder |
return preferred; |
} |
if (builder.next == null && other.next == null) { |
- if (builder.isGetter && other.isSetter) { |
- return new MixedAccessor(builder, other, this); |
- } else if (builder.isSetter && other.isGetter) { |
- return new MixedAccessor(other, builder, this); |
- } |
if (isImport && builder is PrefixBuilder && other is PrefixBuilder) { |
// Handles the case where the same prefix is used for different |
// imports. |
- PrefixBuilder prefix = builder; |
- other.exports.forEach((String name, Builder member) { |
- Builder existing = exports[name]; |
- if (existing != null) { |
- if (existing != member) { |
- member = buildAmbiguousBuilder(name, existing, member, charOffset, |
- isExport: isExport, isImport: isImport); |
- } |
- } |
- prefix.exports[name] = member; |
- }); |
- return builder; |
+ return builder |
+ ..exports.merge(other.exports, |
+ (String name, Builder existing, Builder member) { |
+ return buildAmbiguousBuilder(name, existing, member, charOffset, |
+ isExport: isExport, isImport: isImport); |
+ }); |
} |
} |
if (isExport) { |
@@ -515,11 +543,3 @@ class KernelLibraryBuilder |
assert(mixinApplicationClasses.isEmpty); |
} |
} |
- |
-bool isConstructorName(String name, String className) { |
- if (name.startsWith(className)) { |
- if (name.length == className.length) return true; |
- if (name.startsWith(".", className.length)) return true; |
- } |
- return false; |
-} |