| Index: pkg/compiler/lib/src/js_backend/namer.dart
|
| diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
|
| index 43bb6804b3e4934847540521360696d2f0f7791e..b367c9e4e4f1c97f7215919f5b9b2866c9c5fb35 100644
|
| --- a/pkg/compiler/lib/src/js_backend/namer.dart
|
| +++ b/pkg/compiler/lib/src/js_backend/namer.dart
|
| @@ -514,8 +514,7 @@ class Namer {
|
| /// (see [globalObjectFor]), we currently use a single namespace for all these
|
| /// names.
|
| final NamingScope globalScope = new NamingScope();
|
| - final Map<Element, jsAst.Name> userGlobals =
|
| - new HashMap<Element, jsAst.Name>();
|
| + final Map<Entity, jsAst.Name> userGlobals = new HashMap<Entity, jsAst.Name>();
|
| final Map<String, jsAst.Name> internalGlobals =
|
| new HashMap<String, jsAst.Name>();
|
|
|
| @@ -867,7 +866,7 @@ class Namer {
|
| jsAst.Name fieldAccessorName(FieldElement element) {
|
| return element.isInstanceMember
|
| ? _disambiguateMember(element.memberName)
|
| - : _disambiguateGlobal(element);
|
| + : _disambiguateGlobalMember(element);
|
| }
|
|
|
| /**
|
| @@ -877,19 +876,32 @@ class Namer {
|
| jsAst.Name fieldPropertyName(FieldElement element) {
|
| return element.isInstanceMember
|
| ? instanceFieldPropertyName(element)
|
| - : _disambiguateGlobal(element);
|
| + : _disambiguateGlobalMember(element);
|
| }
|
|
|
| - /**
|
| - * Returns a JavaScript property name used to store [element] on one
|
| - * of the global objects.
|
| - *
|
| - * Should be used together with [globalObjectFor], which denotes the object
|
| - * on which the returned property name should be used.
|
| - */
|
| - jsAst.Name globalPropertyName(Element element) {
|
| - return _disambiguateGlobal(element);
|
| - }
|
| + /// Returns a JavaScript property name used to store the member [element] on
|
| + /// one of the global objects.
|
| + ///
|
| + /// Should be used together with [globalObjectForMember], which denotes the
|
| + /// object on which the returned property name should be used.
|
| + jsAst.Name globalPropertyNameForMember(MemberEntity element) =>
|
| + _disambiguateGlobalMember(element);
|
| +
|
| + /// Returns a JavaScript property name used to store the class [element] on
|
| + /// one of the global objects.
|
| + ///
|
| + /// Should be used together with [globalObjectForClass], which denotes the
|
| + /// object on which the returned property name should be used.
|
| + jsAst.Name globalPropertyNameForClass(ClassEntity element) =>
|
| + _disambiguateGlobalType(element);
|
| +
|
| + /// Returns a JavaScript property name used to store the type (typedef)
|
| + /// [element] on one of the global objects.
|
| + ///
|
| + /// Should be used together with [globalObjectForType], which denotes the
|
| + /// object on which the returned property name should be used.
|
| + jsAst.Name globalPropertyNameForType(TypeDeclarationElement element) =>
|
| + _disambiguateGlobalType(element);
|
|
|
| /**
|
| * Returns the JavaScript property name used to store an instance field.
|
| @@ -1023,16 +1035,30 @@ class Namer {
|
| });
|
| }
|
|
|
| + jsAst.Name _disambiguateGlobalMember(MemberEntity element) {
|
| + return _disambiguateGlobal(element, _proposeNameForMember);
|
| + }
|
| +
|
| + jsAst.Name _disambiguateGlobalType(Entity element) {
|
| + return _disambiguateGlobal(element, _proposeNameForType);
|
| + }
|
| +
|
| /// Returns the disambiguated name for a top-level or static element.
|
| ///
|
| /// The resulting name is unique within the global-member namespace.
|
| - jsAst.Name _disambiguateGlobal(Element element) {
|
| + jsAst.Name _disambiguateGlobal(
|
| + Entity element, String proposeName(Entity element)) {
|
| // TODO(asgerf): We can reuse more short names if we disambiguate with
|
| // a separate namespace for each of the global holder objects.
|
| - element = element.declaration;
|
| + if (element is Element) {
|
| + // Ensures we only work on declarations. Non-[Element] entities do not
|
| + // have the declaration/implementation separation.
|
| + Element e = element;
|
| + element = e.declaration;
|
| + }
|
| jsAst.Name newName = userGlobals[element];
|
| if (newName == null) {
|
| - String proposedName = _proposeNameForGlobal(element);
|
| + String proposedName = proposeName(element);
|
| newName = getFreshName(globalScope, proposedName);
|
| userGlobals[element] = newName;
|
| }
|
| @@ -1247,33 +1273,40 @@ class Namer {
|
| return name;
|
| }
|
|
|
| - /**
|
| - * Returns a proposed name for the given top-level or static element.
|
| - * The returned id is guaranteed to be a valid JavaScript identifier.
|
| - */
|
| - String _proposeNameForGlobal(Element element) {
|
| - assert(!element.isInstanceMember);
|
| - if (element.isGenerativeConstructor) {
|
| - return '${element.enclosingClass.name}\$${element.name}';
|
| + /// Returns a proposed name for the given typedef or class [element].
|
| + /// The returned id is guaranteed to be a valid JavaScript identifier.
|
| + String _proposeNameForType(Entity element) {
|
| + return element.name.replaceAll('+', '_');
|
| + }
|
| +
|
| + /// Returns a proposed name for the given top-level or static member
|
| + /// [element]. The returned id is guaranteed to be a valid JavaScript
|
| + /// identifier.
|
| + String _proposeNameForMember(MemberEntity element) {
|
| + if (element.isConstructor) {
|
| + return _proposeNameForConstructor(element);
|
| + } else if (element.enclosingClass != null) {
|
| + ClassEntity enclosingClass = element.enclosingClass;
|
| + return '${enclosingClass.name}_${element.name}';
|
| }
|
| - if (element.isFactoryConstructor) {
|
| + return element.name.replaceAll('+', '_');
|
| + }
|
| +
|
| + String _proposeNameForConstructor(ConstructorEntity element) {
|
| + String className = element.enclosingClass.name;
|
| + if (element.isGenerativeConstructor) {
|
| + return '${className}\$${element.name}';
|
| + } else {
|
| // TODO(johnniwinther): Change factory name encoding as to not include
|
| // the class-name twice.
|
| - String className = element.enclosingClass.name;
|
| - return '${className}_${Elements.reconstructConstructorName(element)}';
|
| - }
|
| - if (Elements.isStaticOrTopLevel(element)) {
|
| - if (element.isClassMember) {
|
| - ClassElement enclosingClass = element.enclosingClass;
|
| - return '${enclosingClass.name}_${element.name}';
|
| + String constructorName;
|
| + if (element.name == '') {
|
| + constructorName = className;
|
| + } else {
|
| + constructorName = '${className}\$${element.name}';
|
| }
|
| - return element.name.replaceAll('+', '_');
|
| + return '${className}_${constructorName}';
|
| }
|
| - if (element.isLibrary) {
|
| - LibraryElement library = element;
|
| - return _proposeNameForLibrary(library);
|
| - }
|
| - return element.name;
|
| }
|
|
|
| /**
|
| @@ -1356,7 +1389,7 @@ class Namer {
|
| // The unspecialized getInterceptor method can also be accessed through
|
| // its element, so we treat this as a user-space global instead of an
|
| // internal global.
|
| - return _disambiguateGlobal(getInterceptor);
|
| + return _disambiguateGlobalMember(getInterceptor);
|
| }
|
| String suffix = suffixForGetInterceptor(classes);
|
| return _disambiguateInternalGlobal("${getInterceptor.name}\$$suffix");
|
| @@ -1407,14 +1440,14 @@ class Namer {
|
| // To prevent clashes in both namespaces at once, we disambiguate the name
|
| // as a global here, and in [_sanitizeForAnnotations] we ensure that
|
| // ordinary instance members cannot start with `$is` or `$as`.
|
| - return _disambiguateGlobal(element);
|
| + return _disambiguateGlobalType(element);
|
| }
|
|
|
| /// Returns the disambiguated name of [class_].
|
| ///
|
| /// This is both the *runtime type* of the class (see [runtimeTypeName])
|
| /// and a global property name in which to store its JS constructor.
|
| - jsAst.Name className(ClassElement class_) => _disambiguateGlobal(class_);
|
| + jsAst.Name className(ClassElement class_) => _disambiguateGlobalType(class_);
|
|
|
| /// Property name on which [member] can be accessed directly,
|
| /// without clashing with another JS property name.
|
| @@ -1450,10 +1483,10 @@ class Namer {
|
| ///
|
| /// The name is not necessarily unique to [method], since a static method
|
| /// may share its name with an instance method.
|
| - jsAst.Name methodPropertyName(Element method) {
|
| + jsAst.Name methodPropertyName(MethodElement method) {
|
| return method.isInstanceMember
|
| ? instanceMethodName(method)
|
| - : globalPropertyName(method);
|
| + : globalPropertyNameForMember(method);
|
| }
|
|
|
| /// Returns true if [element] is stored in the static state holder
|
| @@ -1461,40 +1494,57 @@ class Namer {
|
| /// there, whereas constants are stored in 'C'. Functions, accessors,
|
| /// classes, etc. are stored in one of the other objects in
|
| /// [reservedGlobalObjectNames].
|
| - bool _isPropertyOfStaticStateHolder(Element element) {
|
| + bool _isPropertyOfStaticStateHolder(MemberEntity element) {
|
| // TODO(ahe): Make sure this method's documentation is always true and
|
| // remove the word "intend".
|
| - return
|
| - // TODO(ahe): Re-write these tests to be positive (so it only returns
|
| - // true for static/top-level mutable fields). Right now, a number of
|
| - // other elements, such as bound closures also live in
|
| - // [staticStateHolder].
|
| - !element.isAccessor &&
|
| - !element.isClass &&
|
| - !element.isTypedef &&
|
| - !element.isConstructor &&
|
| - !element.isFunction &&
|
| - !element.isLibrary;
|
| + if (element is MemberElement) {
|
| + // TODO(johnniwinther): Clean up this method to have a single semantics on
|
| + // entities.
|
| + return
|
| + // TODO(ahe): Re-write these tests to be positive (so it only returns
|
| + // true for static/top-level mutable fields). Right now, a number of
|
| + // other elements, such as bound closures also live in
|
| + // [staticStateHolder].
|
| + !element.isAccessor &&
|
| + !element.isClass &&
|
| + !element.isTypedef &&
|
| + !element.isConstructor &&
|
| + !element.isFunction &&
|
| + !element.isLibrary;
|
| + }
|
| + return element.isField;
|
| }
|
|
|
| /// Returns [staticStateHolder] or one of [reservedGlobalObjectNames].
|
| // TODO(johnniwinther): Verify that the implementation can be changed to
|
| // `globalObjectForLibrary(element.library)`.
|
| String globalObjectForMethod(MethodElement element) =>
|
| - globalObjectFor(element);
|
| + globalObjectForMember(element);
|
|
|
| /// Returns [staticStateHolder] or one of [reservedGlobalObjectNames].
|
| - String globalObjectFor(Element element) {
|
| + String globalObjectForMember(MemberEntity element) {
|
| if (_isPropertyOfStaticStateHolder(element)) return staticStateHolder;
|
| return globalObjectForLibrary(element.library);
|
| }
|
|
|
| + String globalObjectForClass(ClassEntity element) {
|
| + return globalObjectForLibrary(element.library);
|
| + }
|
| +
|
| + String globalObjectForType(Entity element) {
|
| + if (element is TypedefElement) {
|
| + return globalObjectForLibrary(element.library);
|
| + }
|
| + return globalObjectForClass(element);
|
| + }
|
| +
|
| /// Returns the [reservedGlobalObjectNames] for [library].
|
| - String globalObjectForLibrary(LibraryElement library) {
|
| + String globalObjectForLibrary(LibraryEntity library) {
|
| if (library == _commonElements.interceptorsLibrary) return 'J';
|
| - if (library.isInternalLibrary) return 'H';
|
| - if (library.isPlatformLibrary) {
|
| - if ('${library.canonicalUri}' == 'dart:html') return 'W';
|
| + Uri uri = library.canonicalUri;
|
| + if (uri.scheme == 'dart') {
|
| + if (uri.path == 'html') return 'W';
|
| + if (uri.path.startsWith('_')) return 'H';
|
| return 'P';
|
| }
|
| return userGlobalObjects[library.name.hashCode % userGlobalObjects.length];
|
| @@ -1505,9 +1555,9 @@ class Namer {
|
| return new CompoundName([_literalLazyGetterPrefix, name]);
|
| }
|
|
|
| - jsAst.Name lazyInitializerName(Element element) {
|
| - assert(Elements.isStaticOrTopLevelField(element));
|
| - jsAst.Name name = _disambiguateGlobal(element);
|
| + jsAst.Name lazyInitializerName(FieldEntity element) {
|
| + assert(element.isTopLevel || element.isStatic);
|
| + jsAst.Name name = _disambiguateGlobalMember(element);
|
| // These are not real dart getters, so do not use GetterName;
|
| return deriveLazyInitializerName(name);
|
| }
|
|
|