From dee5152f9b270baf3bc5ebd7843da070c12dec3f Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 18 Sep 2012 12:20:23 +0400 Subject: [PATCH] Supporting Unit.VALUE, to replace #() #KT-2358 In Progress --- .../jet/codegen/ExpressionCodegen.java | 2 +- .../org/jetbrains/jet/codegen/StackValue.java | 2 +- .../codegen/intrinsics/IntrinsicMethods.java | 13 +++- .../jet/codegen/intrinsics/UnitValue.java | 51 ++++++++++++ .../TuplesAndFunctionsGenerator.java | 3 +- compiler/frontend/src/jet.src/Tuples.jet | 1 - compiler/frontend/src/jet.src/Unit.jet | 7 ++ .../lang/descriptors/ClassDescriptorImpl.java | 64 +++++++-------- .../lang/types/lang/JetStandardClasses.java | 77 ++++++++++++++++++- compiler/testData/builtin-classes.txt | 6 +- compiler/testData/codegen/tuples/UnitValue.kt | 5 ++ .../diagnostics/tests/tuples/UnitValue.kt | 3 + .../checkers/JetDiagnosticsTestGenerated.java | 5 ++ .../jetbrains/jet/codegen/TupleGenTest.java | 6 ++ runtime/src/jet/StringTemplate.java | 2 +- runtime/src/jet/Tuple0.java | 6 +- 16 files changed, 206 insertions(+), 47 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnitValue.java create mode 100644 compiler/frontend/src/jet.src/Unit.jet create mode 100644 compiler/testData/codegen/tuples/UnitValue.kt create mode 100644 compiler/testData/diagnostics/tests/tuples/UnitValue.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 093b187f77c..48dc90f93fd 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -3367,7 +3367,7 @@ The "returned" value of try expression with no finally is either the last expres throw new UnsupportedOperationException("tuple too large"); } if (entries.size() == 0) { - v.visitFieldInsn(GETSTATIC, "jet/Tuple0", "INSTANCE", "Ljet/Tuple0;"); + v.visitFieldInsn(GETSTATIC, "jet/Tuple0", "VALUE", "Ljet/Tuple0;"); return StackValue.onStack(JET_TUPLE0_TYPE); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 5c1c83a1ff1..bef134fd345 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -310,7 +310,7 @@ public abstract class StackValue { } public static void putTuple0Instance(InstructionAdapter v) { - v.visitFieldInsn(GETSTATIC, "jet/Tuple0", "INSTANCE", "Ljet/Tuple0;"); + v.visitFieldInsn(GETSTATIC, "jet/Tuple0", "VALUE", "Ljet/Tuple0;"); } protected void putAsBoolean(InstructionAdapter v) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java index e1c23ce0b7f..4eea52b6ca4 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -148,16 +148,25 @@ public class IntrinsicMethods { declareIntrinsicProperty(Name.identifier("CharSequence"), Name.identifier("length"), new StringLength()); declareIntrinsicProperty(Name.identifier("String"), Name.identifier("length"), new StringLength()); + Name tuple0Name = JetStandardClasses.getTuple(0).getName(); + intrinsicsMap.registerIntrinsic( + getClassObjectFqName(tuple0Name), + Name.identifier("VALUE"), -1, new UnitValue()); + for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) { intrinsicsMap.registerIntrinsic( - JetStandardClasses.STANDARD_CLASSES_FQNAME.child(type.getRangeTypeName()).toUnsafe().child( - getClassObjectName(type.getRangeTypeName())), + getClassObjectFqName(type.getRangeTypeName()), Name.identifier("EMPTY"), -1, new EmptyRange(type)); } declareArrayMethods(); } + @NotNull + private static FqNameUnsafe getClassObjectFqName(@NotNull Name builtinClassName) { + return JetStandardClasses.STANDARD_CLASSES_FQNAME.child(builtinClassName).toUnsafe().child(getClassObjectName(builtinClassName)); + } + private void declareArrayMethods() { for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnitValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnitValue.java new file mode 100644 index 00000000000..3a74c0d465a --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnitValue.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.Type; +import org.jetbrains.asm4.commons.InstructionAdapter; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.codegen.state.GenerationState; +import org.jetbrains.jet.lang.psi.JetExpression; + +import java.util.List; + +import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JET_TUPLE0_TYPE; + +/** + * @author abreslav + */ +public class UnitValue implements IntrinsicMethod { + + @Override + public StackValue generate( + ExpressionCodegen codegen, + InstructionAdapter v, + @NotNull Type expectedType, + @Nullable PsiElement element, + @Nullable List arguments, + StackValue receiver, + @NotNull GenerationState state + ) { + v.getstatic(JET_TUPLE0_TYPE.getInternalName(), "VALUE", JET_TUPLE0_TYPE.getDescriptor()); + return StackValue.onStack(expectedType); + } +} diff --git a/compiler/frontend/generator/TuplesAndFunctionsGenerator.java b/compiler/frontend/generator/TuplesAndFunctionsGenerator.java index cd3b55a913e..3166c5ade67 100644 --- a/compiler/frontend/generator/TuplesAndFunctionsGenerator.java +++ b/compiler/frontend/generator/TuplesAndFunctionsGenerator.java @@ -22,11 +22,10 @@ import java.io.PrintStream; * @author abreslav */ public class TuplesAndFunctionsGenerator { - private static int TUPLE_COUNT = 23; + private static final int TUPLE_COUNT = 23; private static void generateTuples(PrintStream out, int count) { generated(out); - out.println("public class Tuple0() {}"); for (int i = 1; i < count; i++) { out.print("public class Tuple" + i); out.print("<"); diff --git a/compiler/frontend/src/jet.src/Tuples.jet b/compiler/frontend/src/jet.src/Tuples.jet index ebbecd1e57c..aed69a312ec 100644 --- a/compiler/frontend/src/jet.src/Tuples.jet +++ b/compiler/frontend/src/jet.src/Tuples.jet @@ -3,7 +3,6 @@ package jet -public class Tuple0() {} public class Tuple1(public val _1: T1) {} public class Tuple2(public val _1: T1, public val _2: T2) {} public class Tuple3(public val _1: T1, public val _2: T2, public val _3: T3) {} diff --git a/compiler/frontend/src/jet.src/Unit.jet b/compiler/frontend/src/jet.src/Unit.jet new file mode 100644 index 00000000000..14795ac757a --- /dev/null +++ b/compiler/frontend/src/jet.src/Unit.jet @@ -0,0 +1,7 @@ +package jet + +public class Tuple0 private () { + public class object { + public val VALUE: Tuple0 + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java index c4e04e927c0..f589280efbd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java @@ -25,9 +25,11 @@ import org.jetbrains.jet.lang.resolve.scopes.SubstitutingScope; import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; -import org.jetbrains.jet.lang.types.lang.JetStandardClasses; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * @author abreslav @@ -40,54 +42,54 @@ public class ClassDescriptorImpl extends DeclarationDescriptorNonRootImpl implem private ConstructorDescriptor primaryConstructor; private ReceiverDescriptor implicitReceiver; private final Modality modality; + private ClassDescriptor classObjectDescriptor; + private final ClassKind kind; + + public ClassDescriptorImpl( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull List annotations, + @NotNull Modality modality, + @NotNull Name name + ) { + this(containingDeclaration, ClassKind.CLASS, annotations, modality, name); + } public ClassDescriptorImpl( @NotNull DeclarationDescriptor containingDeclaration, + @NotNull ClassKind kind, @NotNull List annotations, @NotNull Modality modality, @NotNull Name name) { super(containingDeclaration, annotations, name); + this.kind = kind; this.modality = modality; } - public final ClassDescriptorImpl initialize(boolean sealed, - @NotNull List typeParameters, - @NotNull Collection supertypes, - @NotNull JetScope memberDeclarations, - @NotNull Set constructors, - @Nullable ConstructorDescriptor primaryConstructor) { - return initialize(sealed, typeParameters, supertypes, memberDeclarations, constructors, primaryConstructor, getClassType(supertypes)); - } - public final ClassDescriptorImpl initialize(boolean sealed, - @NotNull List typeParameters, - @NotNull Collection supertypes, - @NotNull JetScope memberDeclarations, - @NotNull Set constructors, - @Nullable ConstructorDescriptor primaryConstructor, - @Nullable JetType superclassType) { + public final ClassDescriptorImpl initialize( + boolean sealed, + @NotNull List typeParameters, + @NotNull Collection supertypes, + @NotNull JetScope memberDeclarations, + @NotNull Set constructors, + @Nullable ConstructorDescriptor primaryConstructor + ) { this.typeConstructor = new TypeConstructorImpl(this, getAnnotations(), sealed, getName().getName(), typeParameters, supertypes); this.memberDeclarations = memberDeclarations; this.constructors = constructors; this.primaryConstructor = primaryConstructor; + this.classObjectDescriptor = classObjectDescriptor; return this; } - @NotNull - private JetType getClassType(@NotNull Collection types) { - for (JetType type : types) { - ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(type); - if (classDescriptor != null) { - return type; - } - } - return JetStandardClasses.getAnyType(); - } - public void setPrimaryConstructor(@NotNull ConstructorDescriptor primaryConstructor) { this.primaryConstructor = primaryConstructor; } + public void setClassObjectDescriptor(@NotNull ClassDescriptor classObjectDescriptor) { + this.classObjectDescriptor = classObjectDescriptor; + } + @Override @NotNull public TypeConstructor getTypeConstructor() { @@ -126,18 +128,18 @@ public class ClassDescriptorImpl extends DeclarationDescriptorNonRootImpl implem @Override public JetType getClassObjectType() { - return null; + return getClassObjectDescriptor().getDefaultType(); } @Override public ClassDescriptor getClassObjectDescriptor() { - return null; + return classObjectDescriptor; } @NotNull @Override public ClassKind getKind() { - return ClassKind.CLASS; + return kind; } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/lang/JetStandardClasses.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/lang/JetStandardClasses.java index e7ff6f56e0c..9bf6b06ed00 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/lang/JetStandardClasses.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/lang/JetStandardClasses.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.DescriptorResolver; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; @@ -91,7 +92,6 @@ public class JetStandardClasses { }, JetScope.EMPTY, Collections.singleton(constructorDescriptor), - null, null ); NOTHING_TYPE = new JetTypeImpl(getNothing()); @@ -125,7 +125,6 @@ public class JetStandardClasses { Collections.emptySet(), JetScope.EMPTY, Collections.singleton(constructorDescriptor), - null, null ); ANY_TYPE = new JetTypeImpl(ANY.getTypeConstructor(), new JetScopeImpl() { @@ -201,14 +200,84 @@ public class JetStandardClasses { writableScope, Collections.singleton(constructorDescriptor), null); + + if (i == 0) { + // Unit.VALUE + classDescriptor.setClassObjectDescriptor(createClassObjectForUnit(classDescriptor)); + } + TUPLE_CONSTRUCTORS.add(TUPLE[i].getTypeConstructor()); - constructorDescriptor.initialize(classDescriptor.getTypeConstructor().getParameters(), constructorValueParameters, Visibilities.PUBLIC); + constructorDescriptor.initialize(classDescriptor.getTypeConstructor().getParameters(), constructorValueParameters, i == 0 ? Visibilities.PRIVATE : Visibilities.PUBLIC); constructorDescriptor.setReturnType(classDescriptor.getDefaultType()); } } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + @NotNull + private static ClassDescriptor createClassObjectForUnit(@NotNull ClassDescriptorImpl unitClass) { + ClassDescriptorImpl classObjectDescriptor = new ClassDescriptorImpl( + unitClass, + ClassKind.CLASS_OBJECT, + Collections.emptyList(), + Modality.FINAL, + DescriptorUtils.getClassObjectName(unitClass.getName()) + ); + WritableScopeImpl classObjectMemberScope = new WritableScopeImpl( + JetScope.EMPTY, + classObjectDescriptor, + RedeclarationHandler.DO_NOTHING, + "Unit class object members" + ); + PropertyDescriptor valueProperty = createUnitValueProperty(unitClass, classObjectDescriptor); + classObjectMemberScope.addPropertyDescriptor(valueProperty); + classObjectMemberScope.changeLockLevel(WritableScope.LockLevel.READING); + + ConstructorDescriptorImpl classObjectConstructorDescriptor = new ConstructorDescriptorImpl(classObjectDescriptor, Collections.emptyList(), true); + classObjectConstructorDescriptor.initialize( + Collections.emptyList(), + Collections.emptyList(), + Visibilities.PRIVATE + ); + + classObjectDescriptor.initialize( + /*sealed = */ true, + Collections.emptyList(), + Collections.singleton(getAnyType()), + classObjectMemberScope, + Collections.singleton(classObjectConstructorDescriptor), + classObjectConstructorDescriptor + ); + + classObjectConstructorDescriptor.setReturnType(classObjectDescriptor.getDefaultType()); + + return classObjectDescriptor; + } + + @NotNull + private static PropertyDescriptor createUnitValueProperty( + @NotNull ClassDescriptorImpl unitClass, + @NotNull ClassDescriptorImpl unitClassObject + ) { + PropertyDescriptor valueProperty = new PropertyDescriptor( + unitClassObject, + Collections.emptyList(), + Modality.FINAL, + Visibilities.PUBLIC, + /*isVar = */ false, + Name.identifier("VALUE"), + CallableMemberDescriptor.Kind.DECLARATION); + valueProperty.setType( + unitClass.getDefaultType(), + Collections.emptyList(), + unitClassObject.getImplicitReceiver(), + ReceiverDescriptor.NO_RECEIVER); + PropertyGetterDescriptor getter = DescriptorResolver.createDefaultGetter(valueProperty); + getter.initialize(unitClass.getDefaultType()); + valueProperty.initialize(getter, null); + return valueProperty; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static final int MAX_FUNCTION_ORDER = 22; diff --git a/compiler/testData/builtin-classes.txt b/compiler/testData/builtin-classes.txt index ae5d0a19483..33fab318c8e 100644 --- a/compiler/testData/builtin-classes.txt +++ b/compiler/testData/builtin-classes.txt @@ -1123,7 +1123,11 @@ public open class jet.Throwable : jet.Any { public final fun printStackTrace(): jet.Tuple0 } public final class jet.Tuple0 : jet.Any { - public final /*constructor*/ fun (): jet.Tuple0 + private final /*constructor*/ fun (): jet.Tuple0 + public final class object jet.Tuple0. : jet.Any { + private final /*constructor*/ fun (): jet.Tuple0. + public final val VALUE: jet.Tuple0 + } } public final class jet.Tuple1 : jet.Any { public final /*constructor*/ fun (/*0*/ _1: T1): jet.Tuple1 diff --git a/compiler/testData/codegen/tuples/UnitValue.kt b/compiler/testData/codegen/tuples/UnitValue.kt new file mode 100644 index 00000000000..8037babc462 --- /dev/null +++ b/compiler/testData/codegen/tuples/UnitValue.kt @@ -0,0 +1,5 @@ +fun foo() {} + +fun box(): String { + return if (foo() == Unit.VALUE) "OK" else "Fail" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/tuples/UnitValue.kt b/compiler/testData/diagnostics/tests/tuples/UnitValue.kt new file mode 100644 index 00000000000..720a081353e --- /dev/null +++ b/compiler/testData/diagnostics/tests/tuples/UnitValue.kt @@ -0,0 +1,3 @@ +fun test() { + return Unit.VALUE : Unit +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 6e35aa9de22..76f40268bdb 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -3278,6 +3278,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/tuples/BasicTuples.kt"); } + @TestMetadata("UnitValue.kt") + public void testUnitValue() throws Exception { + doTest("compiler/testData/diagnostics/tests/tuples/UnitValue.kt"); + } + } @TestMetadata("compiler/testData/diagnostics/tests/varargs") diff --git a/compiler/tests/org/jetbrains/jet/codegen/TupleGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/TupleGenTest.java index 49a8c8bd78c..61bd26b809a 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/TupleGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/TupleGenTest.java @@ -22,6 +22,12 @@ public class TupleGenTest extends CodegenTestCase { public void testBasic() { createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); blackBoxFile("/tuples/basic.jet"); +// System.out.println(generateToText()); + } + + public void testUnitValue() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("/tuples/UnitValue.kt"); // System.out.println(generateToText()); } } diff --git a/runtime/src/jet/StringTemplate.java b/runtime/src/jet/StringTemplate.java index a3f5e9f9f26..47b3b49d4c8 100644 --- a/runtime/src/jet/StringTemplate.java +++ b/runtime/src/jet/StringTemplate.java @@ -58,7 +58,7 @@ public class StringTemplate { @Override public Tuple0 invoke(Object o) { builder.append(o); - return Tuple0.INSTANCE; + return Tuple0.VALUE; } }); return builder.toString(); diff --git a/runtime/src/jet/Tuple0.java b/runtime/src/jet/Tuple0.java index b2ef9060651..ca407fee2a1 100644 --- a/runtime/src/jet/Tuple0.java +++ b/runtime/src/jet/Tuple0.java @@ -23,19 +23,19 @@ import org.jetbrains.jet.rt.annotation.AssertInvisibleInResolver; */ @AssertInvisibleInResolver public class Tuple0 extends Tuple { - public static final Tuple0 INSTANCE = new Tuple0(); + public static final Tuple0 VALUE = new Tuple0(); private Tuple0() { } @Override public String toString() { - return "()"; + return "Unit.VALUE"; } @Override public boolean equals(Object o) { - return o == INSTANCE; + return o == VALUE; } @Override