Skip to content

Commit

Permalink
Initial support for records
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 399302681
  • Loading branch information
cushon authored and Javac Team committed Sep 27, 2021
1 parent 3bac9d7 commit ec67a6e
Show file tree
Hide file tree
Showing 16 changed files with 350 additions and 38 deletions.
3 changes: 3 additions & 0 deletions java/com/google/turbine/binder/CanonicalTypeBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@ static SourceTypeBoundClass bind(
}
ImmutableMap<TyVarSymbol, TyVarInfo> typParamTypes =
typeParameters(base.source(), pos, env, sym, base.typeParameterTypes());
ImmutableList<ParamInfo> components =
parameters(base.source(), env, sym, pos, base.components());
ImmutableList<MethodInfo> methods = methods(base.source(), pos, env, sym, base.methods());
ImmutableList<FieldInfo> fields = fields(base.source(), env, sym, base.fields());
return new SourceTypeBoundClass(
interfaceTypes.build(),
superClassType,
typParamTypes,
base.access(),
components,
methods,
fields,
base.owner(),
Expand Down
8 changes: 3 additions & 5 deletions java/com/google/turbine/binder/CompUnitPreprocessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ public static int access(ImmutableSet<TurbineModifier> mods, TurbineTyKind tykin
access |= TurbineFlag.ACC_ABSTRACT | TurbineFlag.ACC_INTERFACE | TurbineFlag.ACC_ANNOTATION;
break;
case RECORD:
// TODO(b/200222393): add support for records
throw new AssertionError(tykind);
access |= TurbineFlag.ACC_SUPER | TurbineFlag.ACC_FINAL;
break;
}
return access;
}
Expand All @@ -198,16 +198,14 @@ private static int innerClassAccess(int enclosing, TyDecl decl) {
case INTERFACE:
case ENUM:
case ANNOTATION:
case RECORD:
access |= TurbineFlag.ACC_STATIC;
break;
case CLASS:
if ((enclosing & (TurbineFlag.ACC_INTERFACE | TurbineFlag.ACC_ANNOTATION)) != 0) {
access |= TurbineFlag.ACC_STATIC;
}
break;
case RECORD:
// TODO(b/200222393): add support for records
throw new AssertionError(decl.tykind());
}

// propagate strictfp to nested types
Expand Down
2 changes: 2 additions & 0 deletions java/com/google/turbine/binder/ConstBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,15 @@ public SourceTypeBoundClass bind() {
env,
log)
.evaluateAnnotations(base.annotations());
ImmutableList<TypeBoundClass.ParamInfo> components = bindParameters(base.components());
ImmutableList<TypeBoundClass.FieldInfo> fields = fields(base.fields());
ImmutableList<MethodInfo> methods = bindMethods(base.methods());
return new SourceTypeBoundClass(
bindTypes(base.interfaceTypes()),
base.superClassType() != null ? bindType(base.superClassType()) : null,
bindTypeParameters(base.typeParameterTypes()),
base.access(),
components,
methods,
fields,
base.owner(),
Expand Down
22 changes: 12 additions & 10 deletions java/com/google/turbine/binder/DisambiguateTypeAnnotations.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public static SourceTypeBoundClass bind(
base.superClassType(),
base.typeParameterTypes(),
base.access(),
bindParameters(env, base.components(), TurbineElementType.RECORD_COMPONENT),
bindMethods(env, base.methods()),
bindFields(env, base.fields()),
base.owner(),
Expand Down Expand Up @@ -112,33 +113,34 @@ private static MethodInfo bindMethod(Env<ClassSymbol, TypeBoundClass> env, Metho
base.sym(),
base.tyParams(),
returnType,
bindParameters(env, base.parameters()),
bindParameters(env, base.parameters(), TurbineElementType.PARAMETER),
base.exceptions(),
base.access(),
base.defaultValue(),
base.decl(),
declarationAnnotations.build(),
base.receiver() != null ? bindParam(env, base.receiver()) : null);
base.receiver() != null
? bindParam(env, base.receiver(), TurbineElementType.PARAMETER)
: null);
}

private static ImmutableList<ParamInfo> bindParameters(
Env<ClassSymbol, TypeBoundClass> env, ImmutableList<ParamInfo> params) {
Env<ClassSymbol, TypeBoundClass> env,
ImmutableList<ParamInfo> params,
TurbineElementType declarationTarget) {
ImmutableList.Builder<ParamInfo> result = ImmutableList.builder();
for (ParamInfo param : params) {
result.add(bindParam(env, param));
result.add(bindParam(env, param, declarationTarget));
}
return result.build();
}

private static ParamInfo bindParam(Env<ClassSymbol, TypeBoundClass> env, ParamInfo base) {
private static ParamInfo bindParam(
Env<ClassSymbol, TypeBoundClass> env, ParamInfo base, TurbineElementType declarationTarget) {
ImmutableList.Builder<AnnoInfo> declarationAnnotations = ImmutableList.builder();
Type type =
disambiguate(
env,
TurbineElementType.PARAMETER,
base.type(),
base.annotations(),
declarationAnnotations);
env, declarationTarget, base.type(), base.annotations(), declarationAnnotations);
return new ParamInfo(base.sym(), type, declarationAnnotations.build(), base.access());
}

Expand Down
3 changes: 3 additions & 0 deletions java/com/google/turbine/binder/HierarchyBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ private SourceHeaderBoundClass bind() {
case CLASS:
superclass = !origin.equals(ClassSymbol.OBJECT) ? ClassSymbol.OBJECT : null;
break;
case RECORD:
superclass = ClassSymbol.RECORD;
break;
default:
throw new AssertionError(decl.tykind());
}
Expand Down
159 changes: 145 additions & 14 deletions java/com/google/turbine/binder/TypeBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.google.turbine.binder;

import static com.google.common.collect.Iterables.getLast;
import static java.util.Objects.requireNonNull;

import com.google.common.base.Joiner;
Expand Down Expand Up @@ -215,6 +216,9 @@ private SourceTypeBoundClass bind() {
}
superClassType = Type.ClassTy.OBJECT;
break;
case RECORD:
superClassType = Type.ClassTy.asNonParametricClassTy(ClassSymbol.RECORD);
break;
default:
throw new AssertionError(base.decl().tykind());
}
Expand All @@ -229,11 +233,18 @@ private SourceTypeBoundClass bind() {
.append(new SingletonScope(base.decl().name().value(), owner))
.append(new ClassMemberScope(owner, env));

List<MethodInfo> methods =
SyntheticMethods syntheticMethods = new SyntheticMethods();

ImmutableList<ParamInfo> components =
bindComponents(scope, syntheticMethods, base.decl().components());

ImmutableList.Builder<MethodInfo> methods =
ImmutableList.<MethodInfo>builder()
.addAll(syntheticMethods())
.addAll(bindMethods(scope, base.decl().members()))
.build();
.addAll(syntheticMethods(syntheticMethods, components))
.addAll(bindMethods(scope, base.decl().members()));
if (base.kind().equals(TurbineTyKind.RECORD)) {
methods.addAll(syntheticRecordMethods(syntheticMethods, components));
}

ImmutableList<FieldInfo> fields = bindFields(scope, base.decl().members());

Expand All @@ -242,7 +253,8 @@ private SourceTypeBoundClass bind() {
superClassType,
typeParameterTypes,
base.access(),
ImmutableList.copyOf(methods),
components,
methods.build(),
fields,
base.owner(),
base.kind(),
Expand All @@ -257,23 +269,73 @@ private SourceTypeBoundClass bind() {
base.decl());
}

/**
* A generated for synthetic {@link MethodSymbol}s.
*
* <p>Each {@link MethodSymbol} contains an index into its enclosing class, to enable comparing
* the symbols for equality. For synthetic methods we use an arbitrary unique negative index.
*/
private static class SyntheticMethods {

private int idx = -1;

MethodSymbol create(ClassSymbol owner, String name) {
return new MethodSymbol(idx--, owner, name);
}
}

private ImmutableList<ParamInfo> bindComponents(
CompoundScope scope,
SyntheticMethods syntheticMethods,
ImmutableList<Tree.VarDecl> components) {
ImmutableList.Builder<ParamInfo> result = ImmutableList.builder();
for (Tree.VarDecl p : components) {
int access = 0;
for (TurbineModifier m : p.mods()) {
access |= m.flag();
}
MethodSymbol msym = syntheticMethods.create(owner, "");
ParamInfo param =
new ParamInfo(
new ParamSymbol(msym, p.name().value()),
bindTy(scope, p.ty()),
bindAnnotations(scope, p.annos()),
access);
result.add(param);
}
return result.build();
}

/** Collect synthetic and implicit methods, including default constructors and enum methods. */
ImmutableList<MethodInfo> syntheticMethods() {
ImmutableList<MethodInfo> syntheticMethods(
SyntheticMethods syntheticMethods, ImmutableList<ParamInfo> components) {
switch (base.kind()) {
case CLASS:
return maybeDefaultConstructor();
return maybeDefaultConstructor(syntheticMethods);
case RECORD:
return maybeDefaultRecordConstructor(syntheticMethods, components);
case ENUM:
return syntheticEnumMethods();
return syntheticEnumMethods(syntheticMethods);
default:
return ImmutableList.of();
}
}

private ImmutableList<MethodInfo> maybeDefaultConstructor() {
private ImmutableList<MethodInfo> maybeDefaultRecordConstructor(
SyntheticMethods syntheticMethods, ImmutableList<ParamInfo> components) {
if (hasConstructor()) {
return ImmutableList.of();
}
MethodSymbol symbol = new MethodSymbol(-1, owner, "<init>");
MethodSymbol symbol = syntheticMethods.create(owner, "<init>");
return ImmutableList.of(
syntheticConstructor(symbol, components, TurbineVisibility.fromAccess(base.access())));
}

private ImmutableList<MethodInfo> maybeDefaultConstructor(SyntheticMethods syntheticMethods) {
if (hasConstructor()) {
return ImmutableList.of();
}
MethodSymbol symbol = syntheticMethods.create(owner, "<init>");
ImmutableList<ParamInfo> formals;
if (hasEnclosingInstance(base)) {
formals = ImmutableList.of(enclosingInstanceParameter(symbol));
Expand All @@ -288,6 +350,10 @@ private MethodInfo syntheticConstructor(
MethodSymbol symbol, ImmutableList<ParamInfo> formals, TurbineVisibility visibility) {
int access = visibility.flag();
access |= (base.access() & TurbineFlag.ACC_STRICT);
if (!formals.isEmpty()
&& (getLast(formals).access() & TurbineFlag.ACC_VARARGS) == TurbineFlag.ACC_VARARGS) {
access |= TurbineFlag.ACC_VARARGS;
}
return new MethodInfo(
symbol,
ImmutableMap.of(),
Expand Down Expand Up @@ -341,15 +407,15 @@ private static ImmutableList<ParamInfo> enumCtorParams(MethodSymbol owner) {
TurbineFlag.ACC_SYNTHETIC));
}

private ImmutableList<MethodInfo> syntheticEnumMethods() {
private ImmutableList<MethodInfo> syntheticEnumMethods(SyntheticMethods syntheticMethods) {
ImmutableList.Builder<MethodInfo> methods = ImmutableList.builder();
int access = 0;
access |= (base.access() & TurbineFlag.ACC_STRICT);
if (!hasConstructor()) {
MethodSymbol symbol = new MethodSymbol(-1, owner, "<init>");
MethodSymbol symbol = syntheticMethods.create(owner, "<init>");
methods.add(syntheticConstructor(symbol, enumCtorParams(symbol), TurbineVisibility.PRIVATE));
}
MethodSymbol valuesMethod = new MethodSymbol(-2, owner, "values");
MethodSymbol valuesMethod = syntheticMethods.create(owner, "values");
methods.add(
new MethodInfo(
valuesMethod,
Expand All @@ -362,7 +428,7 @@ private ImmutableList<MethodInfo> syntheticEnumMethods() {
null,
ImmutableList.of(),
null));
MethodSymbol valueOfMethod = new MethodSymbol(-3, owner, "valueOf");
MethodSymbol valueOfMethod = syntheticMethods.create(owner, "valueOf");
methods.add(
new MethodInfo(
valueOfMethod,
Expand All @@ -383,6 +449,71 @@ private ImmutableList<MethodInfo> syntheticEnumMethods() {
return methods.build();
}

private ImmutableList<MethodInfo> syntheticRecordMethods(
SyntheticMethods syntheticMethods, ImmutableList<ParamInfo> components) {
ImmutableList.Builder<MethodInfo> methods = ImmutableList.builder();
MethodSymbol toStringMethod = syntheticMethods.create(owner, "toString");
methods.add(
new MethodInfo(
toStringMethod,
ImmutableMap.of(),
Type.ClassTy.STRING,
ImmutableList.of(),
ImmutableList.of(),
TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_FINAL,
null,
null,
ImmutableList.of(),
null));
MethodSymbol hashCodeMethod = syntheticMethods.create(owner, "hashCode");
methods.add(
new MethodInfo(
hashCodeMethod,
ImmutableMap.of(),
Type.PrimTy.create(TurbineConstantTypeKind.INT, ImmutableList.of()),
ImmutableList.of(),
ImmutableList.of(),
TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_FINAL,
null,
null,
ImmutableList.of(),
null));
MethodSymbol equalsMethod = syntheticMethods.create(owner, "equals");
methods.add(
new MethodInfo(
equalsMethod,
ImmutableMap.of(),
Type.PrimTy.create(TurbineConstantTypeKind.BOOLEAN, ImmutableList.of()),
ImmutableList.of(
new ParamInfo(
new ParamSymbol(equalsMethod, "other"),
Type.ClassTy.OBJECT,
ImmutableList.of(),
TurbineFlag.ACC_MANDATED)),
ImmutableList.of(),
TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_FINAL,
null,
null,
ImmutableList.of(),
null));
for (ParamInfo c : components) {
MethodSymbol componentMethod = syntheticMethods.create(owner, c.name());
methods.add(
new MethodInfo(
componentMethod,
ImmutableMap.of(),
c.type(),
ImmutableList.of(),
ImmutableList.of(),
TurbineFlag.ACC_PUBLIC,
null,
null,
c.annotations(),
null));
}
return methods.build();
}

private boolean hasConstructor() {
for (Tree m : base.decl().members()) {
if (m.kind() != Kind.METH_DECL) {
Expand Down
Loading

0 comments on commit ec67a6e

Please sign in to comment.