Skip to content

Commit a0d99c4

Browse files
rlublecopybara-github
authored andcommitted
Provide the ordinal value for enums constants in the type model.
PiperOrigin-RevId: 606377591
1 parent 02e381a commit a0d99c4

12 files changed

+96
-80
lines changed

transpiler/java/com/google/j2cl/transpiler/ast/AstUtils.java

+1
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,7 @@ public static FieldDescriptor getEnumOrdinalConstantFieldDescriptor(
10291029
.setName("$ordinal_" + fieldDescriptor.getName())
10301030
.setEnumConstant(false)
10311031
.setCompileTimeConstant(true)
1032+
.setConstantValue(fieldDescriptor.getEnumOrdinalValue())
10321033
.setSynthetic(true)
10331034
.setTypeDescriptor(PrimitiveTypes.INT)
10341035
.setOriginalJsInfo(JsInfo.NONE)

transpiler/java/com/google/j2cl/transpiler/ast/Field.java

+1-20
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package com.google.j2cl.transpiler.ast;
1717

1818
import static com.google.common.base.Preconditions.checkNotNull;
19-
import static com.google.common.base.Preconditions.checkState;
2019

2120
import com.google.j2cl.common.SourcePosition;
2221
import com.google.j2cl.common.visitor.Processor;
@@ -32,20 +31,16 @@ public class Field extends Member {
3231
@Visitable @Nullable Expression initializer;
3332
// TODO(b/112150736): generalize concept of the source position for names to members.
3433
private final SourcePosition nameSourcePosition;
35-
// Only valid for enum fields, where it is >= 0.
36-
private int enumOrdinal;
37-
34+
3835
private Field(
3936
SourcePosition sourcePosition,
4037
FieldDescriptor fieldDescriptor,
4138
Expression initializer,
42-
int enumOrdinal,
4339
SourcePosition nameSourcePosition) {
4440
super(sourcePosition);
4541
this.fieldDescriptor = checkNotNull(fieldDescriptor);
4642
this.initializer = initializer;
4743
this.nameSourcePosition = checkNotNull(nameSourcePosition);
48-
this.enumOrdinal = enumOrdinal;
4944
}
5045

5146
@Override
@@ -99,17 +94,6 @@ public boolean isEnumField() {
9994
return getDescriptor().isEnumConstant();
10095
}
10196

102-
public void setEnumOrdinal(int ordinal) {
103-
checkState(isEnumField());
104-
this.enumOrdinal = ordinal;
105-
}
106-
107-
public int getEnumOrdinal() {
108-
checkState(isEnumField());
109-
checkState(enumOrdinal != -1);
110-
return enumOrdinal;
111-
}
112-
11397
@Override
11498
Node acceptInternal(Processor processor) {
11599
return Visitor_Field.visit(processor, this);
@@ -121,15 +105,13 @@ public static class Builder {
121105
private Expression initializer;
122106
private SourcePosition sourcePosition;
123107
private SourcePosition nameSourcePosition = SourcePosition.NONE;
124-
private int enumOrdinal = -1;
125108

126109
public static Builder from(Field field) {
127110
Builder builder = new Builder();
128111
builder.fieldDescriptor = field.getDescriptor();
129112
builder.initializer = field.getInitializer();
130113
builder.sourcePosition = field.getSourcePosition();
131114
builder.nameSourcePosition = field.getNameSourcePosition();
132-
builder.enumOrdinal = field.enumOrdinal;
133115
return builder;
134116
}
135117

@@ -170,7 +152,6 @@ public Field build() {
170152
sourcePosition,
171153
fieldDescriptor,
172154
initializer,
173-
enumOrdinal,
174155
nameSourcePosition);
175156
}
176157
}

transpiler/java/com/google/j2cl/transpiler/ast/FieldDescriptor.java

+18
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
*/
1616
package com.google.j2cl.transpiler.ast;
1717

18+
import static com.google.common.base.Preconditions.checkNotNull;
1819
import static com.google.common.base.Preconditions.checkState;
1920

2021
import com.google.auto.value.AutoValue;
2122
import com.google.auto.value.extension.memoized.Memoized;
23+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
2224
import com.google.j2cl.common.ThreadLocalInterner;
2325
import java.util.Map;
2426
import java.util.Optional;
@@ -134,6 +136,7 @@ public boolean isCapture() {
134136
|| getOrigin() == FieldOrigin.SYNTHETIC_OUTER_FIELD;
135137
}
136138

139+
@Override
137140
public boolean isJsProperty() {
138141
return getJsInfo().getJsMemberType() == JsMemberType.PROPERTY;
139142
}
@@ -175,6 +178,20 @@ public String getMangledName() {
175178
return computePropertyMangledName();
176179
}
177180

181+
@Memoized
182+
public Literal getEnumOrdinalValue() {
183+
checkState(isEnumConstant());
184+
if (!isDeclaration()) {
185+
return getDeclarationDescriptor().getEnumOrdinalValue();
186+
}
187+
188+
return checkNotNull(
189+
getEnclosingTypeDescriptor()
190+
.getTypeDeclaration()
191+
.getOrdinalValueByEnumFieldName()
192+
.get(getName()));
193+
}
194+
178195
@Override
179196
public FieldDescriptor specializeTypeVariables(
180197
Map<TypeVariable, TypeDescriptor> applySpecializedTypeArgumentByTypeParameters) {
@@ -264,6 +281,7 @@ public abstract Builder setEnclosingTypeDescriptor(
264281

265282
public abstract Builder setOrigin(FieldOrigin fieldOrigin);
266283

284+
@CanIgnoreReturnValue
267285
public Builder setDeclarationDescriptor(FieldDescriptor declarationFieldDescriptor) {
268286
return setDeclarationDescriptorOrNullIfSelf(declarationFieldDescriptor);
269287
}

transpiler/java/com/google/j2cl/transpiler/ast/TypeDeclaration.java

+14
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.google.common.base.Joiner;
2525
import com.google.common.base.Splitter;
2626
import com.google.common.collect.ImmutableList;
27+
import com.google.common.collect.ImmutableMap;
2728
import com.google.common.collect.Iterables;
2829
import com.google.common.collect.Streams;
2930
import com.google.j2cl.common.ThreadLocalInterner;
@@ -758,6 +759,19 @@ public ImmutableList<FieldDescriptor> getDeclaredFieldDescriptors() {
758759
return getDeclaredFieldDescriptorsFactory().get(this);
759760
}
760761

762+
@Memoized
763+
ImmutableMap<String, Literal> getOrdinalValueByEnumFieldName() {
764+
ImmutableMap.Builder<String, Literal> immutableMapBuilder = ImmutableMap.builder();
765+
int ordinal = 0;
766+
for (FieldDescriptor fieldDescriptor : getDeclaredFieldDescriptors()) {
767+
if (!fieldDescriptor.isEnumConstant()) {
768+
continue;
769+
}
770+
immutableMapBuilder.put(fieldDescriptor.getName(), NumberLiteral.fromInt(ordinal++));
771+
}
772+
return immutableMapBuilder.buildOrThrow();
773+
}
774+
761775
/**
762776
* The list of fields declared in the type. Note: this does not include methods synthetic fields
763777
* (like captures) nor supertype fields.

transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JdtEnvironment.java

+33-37
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import java.util.ArrayList;
5757
import java.util.Arrays;
5858
import java.util.Collection;
59+
import java.util.Comparator;
5960
import java.util.HashMap;
6061
import java.util.List;
6162
import java.util.Map;
@@ -1029,18 +1030,6 @@ private DeclaredTypeDescriptor createDeclaredType(
10291030
}
10301031
checkArgument(typeBinding.isClass() || typeBinding.isInterface() || typeBinding.isEnum());
10311032

1032-
Supplier<ImmutableList<MethodDescriptor>> declaredMethods =
1033-
() ->
1034-
Arrays.stream(typeBinding.getDeclaredMethods())
1035-
.map(this::createMethodDescriptor)
1036-
.collect(toImmutableList());
1037-
1038-
Supplier<ImmutableList<FieldDescriptor>> declaredFields =
1039-
() ->
1040-
Arrays.stream(typeBinding.getDeclaredFields())
1041-
.map(this::createFieldDescriptor)
1042-
.collect(toImmutableList());
1043-
10441033
TypeDeclaration typeDeclaration = createDeclarationForType(typeBinding.getTypeDeclaration());
10451034

10461035
DeclaredTypeDescriptor enclosingTypeDescriptor =
@@ -1065,8 +1054,10 @@ private DeclaredTypeDescriptor createDeclaredType(
10651054
DeclaredTypeDescriptor.class))
10661055
.setTypeArgumentDescriptors(
10671056
getTypeArgumentTypeDescriptors(typeBinding, inNullMarkedScope))
1068-
.setDeclaredFieldDescriptorsFactory(declaredFields)
1069-
.setDeclaredMethodDescriptorsFactory(declaredMethods)
1057+
.setDeclaredFieldDescriptorsFactory(
1058+
() -> createFieldDescriptorsOrderedById(typeBinding.getDeclaredFields()))
1059+
.setDeclaredMethodDescriptorsFactory(
1060+
() -> createMethodDescriptors(typeBinding.getDeclaredMethods()))
10701061
.setSingleAbstractMethodDescriptorFactory(() -> getFunctionInterfaceMethod(typeBinding))
10711062
.build();
10721063
putTypeDescriptorInCache(inNullMarkedScope, typeBinding, typeDescriptor);
@@ -1175,19 +1166,6 @@ public TypeDeclaration createDeclarationForType(final ITypeBinding typeBinding)
11751166
boolean isAbstract = isAbstract(typeBinding);
11761167
boolean isFinal = isFinal(typeBinding);
11771168

1178-
Supplier<ImmutableList<MethodDescriptor>> declaredMethods =
1179-
() ->
1180-
Arrays.stream(typeBinding.getDeclaredMethods())
1181-
.map(this::createMethodDescriptor)
1182-
.collect(toImmutableList());
1183-
;
1184-
1185-
Supplier<ImmutableList<FieldDescriptor>> declaredFields =
1186-
() ->
1187-
Arrays.stream(typeBinding.getDeclaredFields())
1188-
.map(this::createFieldDescriptor)
1189-
.collect(toImmutableList());
1190-
11911169
boolean isNullMarked = isNullMarked(typeBinding);
11921170
IBinding declaringMemberBinding = getDeclaringMethodOrFieldBinding(typeBinding);
11931171

@@ -1242,17 +1220,12 @@ public TypeDeclaration createDeclarationForType(final ITypeBinding typeBinding)
12421220
.map(TypeVariable::toNonNullable)
12431221
.collect(toImmutableList()))
12441222
.setVisibility(getVisibility(typeBinding))
1245-
.setDeclaredMethodDescriptorsFactory(declaredMethods)
1246-
.setDeclaredFieldDescriptorsFactory(declaredFields)
1223+
.setDeclaredMethodDescriptorsFactory(
1224+
() -> createMethodDescriptors(typeBinding.getDeclaredMethods()))
1225+
.setDeclaredFieldDescriptorsFactory(
1226+
() -> createFieldDescriptorsOrderedById(typeBinding.getDeclaredFields()))
12471227
.setMemberTypeDeclarationsFactory(
1248-
() -> {
1249-
if (typeBinding.getDeclaredTypes() == null) {
1250-
return ImmutableList.of();
1251-
}
1252-
return Arrays.stream(typeBinding.getDeclaredTypes())
1253-
.map(this::createDeclarationForType)
1254-
.collect(ImmutableList.toImmutableList());
1255-
})
1228+
() -> createTypeDeclarations(typeBinding.getDeclaredTypes()))
12561229
.setUnusableByJsSuppressed(
12571230
JsInteropAnnotationUtils.isUnusableByJsSuppressed(typeBinding))
12581231
.setDeprecated(isDeprecated(typeBinding))
@@ -1261,6 +1234,29 @@ public TypeDeclaration createDeclarationForType(final ITypeBinding typeBinding)
12611234
return typeDeclaration;
12621235
}
12631236

1237+
private ImmutableList<MethodDescriptor> createMethodDescriptors(IMethodBinding[] methodBindings) {
1238+
return Arrays.stream(methodBindings)
1239+
.map(this::createMethodDescriptor)
1240+
.collect(toImmutableList());
1241+
}
1242+
1243+
private ImmutableList<FieldDescriptor> createFieldDescriptorsOrderedById(
1244+
IVariableBinding[] fieldBindings) {
1245+
return Arrays.stream(fieldBindings)
1246+
.sorted(Comparator.comparing(IVariableBinding::getVariableId))
1247+
.map(this::createFieldDescriptor)
1248+
.collect(toImmutableList());
1249+
}
1250+
1251+
private ImmutableList<TypeDeclaration> createTypeDeclarations(ITypeBinding[] typeBindings) {
1252+
if (typeBindings == null) {
1253+
return ImmutableList.of();
1254+
}
1255+
return Arrays.stream(typeBindings)
1256+
.map(this::createDeclarationForType)
1257+
.collect(ImmutableList.toImmutableList());
1258+
}
1259+
12641260
private boolean isNullMarked(ITypeBinding typeBinding) {
12651261
return hasNullMarkedAnnotation(typeBinding)
12661262
|| packageAnnotationsResolver.isNullMarked(typeBinding.getPackage().getName());

transpiler/java/com/google/j2cl/transpiler/passes/NormalizeEnumClasses.java

+8-12
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import com.google.j2cl.transpiler.ast.MethodCall;
3030
import com.google.j2cl.transpiler.ast.NewInstance;
3131
import com.google.j2cl.transpiler.ast.Node;
32-
import com.google.j2cl.transpiler.ast.NumberLiteral;
3332
import com.google.j2cl.transpiler.ast.PrimitiveTypes;
3433
import com.google.j2cl.transpiler.ast.RuntimeMethods;
3534
import com.google.j2cl.transpiler.ast.StringLiteral;
@@ -150,23 +149,20 @@ private static void initJavaLangEnumField(
150149

151150
/** Creates constant static fields to hold the enum ordinal constants. */
152151
private static void createEnumOrdinalConstants(Type type) {
153-
int currentOrdinal = 0;
154-
for (Field enumField : type.getEnumFields()) {
155-
enumField.setEnumOrdinal(currentOrdinal);
152+
// Traverse in reverse order so that the ordinal constant fields are inserted in ascending
153+
// ordinal order.
154+
for (Field enumField : type.getEnumFields().reverse()) {
156155

157-
FieldDescriptor ordinalConstantFieldDescriptor =
158-
AstUtils.getEnumOrdinalConstantFieldDescriptor(enumField.getDescriptor());
156+
FieldDescriptor enumFieldDescriptor = enumField.getDescriptor();
159157
// Create a constant field to hold the ordinal for the current enum value.
160158
type.addMember(
161-
// These field need to be defined at the beginning because they can be referenced by enum
159+
// These fields need to be defined at the beginning because they can be referenced by enum
162160
// constant initializers that are already part of the load time statements.
163-
currentOrdinal,
164-
Field.Builder.from(ordinalConstantFieldDescriptor)
161+
0,
162+
Field.Builder.from(AstUtils.getEnumOrdinalConstantFieldDescriptor(enumFieldDescriptor))
165163
.setSourcePosition(enumField.getSourcePosition())
166-
.setInitializer(NumberLiteral.fromInt(enumField.getEnumOrdinal()))
164+
.setInitializer(enumFieldDescriptor.getEnumOrdinalValue())
167165
.build());
168-
169-
currentOrdinal++;
170166
}
171167
}
172168

transpiler/java/com/google/j2cl/transpiler/passes/NormalizeJsEnums.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@
2525
import com.google.j2cl.transpiler.ast.Expression;
2626
import com.google.j2cl.transpiler.ast.Field;
2727
import com.google.j2cl.transpiler.ast.FieldAccess;
28+
import com.google.j2cl.transpiler.ast.FieldDescriptor;
2829
import com.google.j2cl.transpiler.ast.FieldDescriptor.FieldOrigin;
2930
import com.google.j2cl.transpiler.ast.Method;
3031
import com.google.j2cl.transpiler.ast.MethodCall;
3132
import com.google.j2cl.transpiler.ast.MethodDescriptor;
3233
import com.google.j2cl.transpiler.ast.NewInstance;
3334
import com.google.j2cl.transpiler.ast.Node;
34-
import com.google.j2cl.transpiler.ast.NumberLiteral;
3535
import com.google.j2cl.transpiler.ast.RuntimeMethods;
3636
import com.google.j2cl.transpiler.ast.Type;
3737
import com.google.j2cl.transpiler.ast.TypeDescriptor;
@@ -115,14 +115,15 @@ private static Expression getJsEnumConstantValue(Field field) {
115115
checkState(field.isEnumField());
116116

117117
List<Expression> arguments = ((NewInstance) field.getInitializer()).getArguments();
118-
if (field.getDescriptor().getEnclosingTypeDescriptor().getJsEnumInfo().hasCustomValue()) {
118+
FieldDescriptor fieldDescriptor = field.getDescriptor();
119+
if (fieldDescriptor.getEnclosingTypeDescriptor().getJsEnumInfo().hasCustomValue()) {
119120
checkState(arguments.size() == 3);
120121
Expression constantValue = arguments.get(2);
121122
checkState(constantValue.isCompileTimeConstant());
122123
return constantValue;
123124
} else {
124125
checkState(arguments.size() == 2);
125-
return NumberLiteral.fromInt(field.getEnumOrdinal());
126+
return fieldDescriptor.getEnumOrdinalValue();
126127
}
127128
}
128129

transpiler/java/com/google/j2cl/transpiler/passes/NormalizeSwitchStatements.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,12 @@ private static SwitchCase convertToOrdinalCase(SwitchCase switchCase) {
8787
return switchCase;
8888
}
8989

90-
FieldAccess enumField = (FieldAccess) switchCase.getCaseExpression();
90+
FieldAccess enumFieldAccess = (FieldAccess) switchCase.getCaseExpression();
9191
return SwitchCase.Builder.from(switchCase)
9292
.setCaseExpression(
93-
FieldAccess.Builder.from(enumField)
94-
.setTarget(AstUtils.getEnumOrdinalConstantFieldDescriptor(enumField.getTarget()))
93+
FieldAccess.Builder.from(enumFieldAccess)
94+
.setTarget(
95+
AstUtils.getEnumOrdinalConstantFieldDescriptor(enumFieldAccess.getTarget()))
9596
.build())
9697
.build();
9798
}

transpiler/java/com/google/j2cl/transpiler/passes/PropagateConstants.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,17 @@
3232
import java.util.Map;
3333
import javax.annotation.Nullable;
3434

35-
/** Propagates compile time constant fields. */
35+
/**
36+
* Propagates constant fields.
37+
*
38+
* <p>This pass propagates fields that are either compile time constants or that are final static
39+
* fields initialized to a string or class literal.
40+
*
41+
* <p>Some static final fields end up being initialized to string literal as a result of previous
42+
* passes. E.g. System.getProperty calls get rewritten into literals and might become the
43+
* initializers of a static final fields. In fact this is the approach that has the checks in
44+
* InternalPreconditions removed in optimized builds at generation time.
45+
*/
3646
public class PropagateConstants extends LibraryNormalizationPass {
3747

3848
@Override

transpiler/java/com/google/j2cl/transpiler/passes/VerifyNormalizedUnits.java

-2
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,6 @@ public void exitField(Field field) {
106106
// JsEnum only contains the enum fields.
107107
checkState(!getCurrentType().isJsEnum() || field.isStatic());
108108
}
109-
// Non-native enum fields have a non negative ordinal.
110-
checkState(field.isNative() || !field.isEnumField() || field.getEnumOrdinal() >= 0);
111109
}
112110

113111
public void checkMember(Member member) {

transpiler/javatests/com/google/j2cl/readable/java/autovalue/output_closure/SimpleAutoValue.impl.java.js.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class SimpleAutoValue extends ValueType {
104104
$$int = goog.module.get('vmbootstrap.primitives.$int$impl');
105105
}
106106
}
107-
SimpleAutoValue.prototype.$excluded_fields = [reflect.objectProperty('f_field1__autovalue_SimpleAutoValue_', SimpleAutoValue), reflect.objectProperty('f_field2__autovalue_SimpleAutoValue_', SimpleAutoValue), reflect.objectProperty('f_intField__autovalue_SimpleAutoValue_', SimpleAutoValue)];
107+
SimpleAutoValue.prototype.$excluded_fields = [reflect.objectProperty('f_intField__autovalue_SimpleAutoValue_', SimpleAutoValue), reflect.objectProperty('f_field1__autovalue_SimpleAutoValue_', SimpleAutoValue), reflect.objectProperty('f_field2__autovalue_SimpleAutoValue_', SimpleAutoValue)];
108108
$Util.$setClassMetadata(SimpleAutoValue, 'autovalue.SimpleAutoValue');
109109

110110
exports = SimpleAutoValue;

0 commit comments

Comments
 (0)