diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 81065acdc19..c91711ef870 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -21,7 +21,6 @@ import com.google.common.collect.Multimap; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; -import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; @@ -958,6 +957,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (resolutionResults.isSuccess()) { FunctionDescriptor equals = resolutionResults.getResultingCall().getResultingDescriptor(); context.trace.record(REFERENCE_TARGET, operationSign, equals); + context.trace.record(RESOLVED_CALL, operationSign, resolutionResults.getResultingCall()); if (ensureBooleanResult(operationSign, name, equals.getReturnType(), context)) { ensureNonemptyIntersectionOfOperandTypes(expression, context); } diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java index 67c073bfb89..7c78890e80d 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java @@ -22,7 +22,7 @@ public final class EqualsTest extends AbstractExpressionTest { super("equals/"); } - public void TODO_testCustomEqualsMethod() throws Exception { + public void testCustomEqualsMethod() throws Exception { fooBoxTest(); } diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibTestBase.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibTestBase.java index 4fef9e739f3..4890498c7ab 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibTestBase.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibTestBase.java @@ -17,18 +17,23 @@ */ package org.jetbrains.k2js.test.semantics; +import com.google.common.base.Function; import com.google.common.collect.Lists; +import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.cli.common.ExitCode; +import org.jetbrains.jet.cli.js.K2JSCompiler; +import org.jetbrains.jet.cli.js.K2JSCompilerArguments; import org.jetbrains.k2js.config.Config; import org.jetbrains.k2js.config.EcmaVersion; -import org.jetbrains.k2js.facade.MainCallParameters; import org.jetbrains.k2js.test.SingleFileTranslationTest; -import org.jetbrains.k2js.test.utils.TranslationUtils; +import javax.annotation.Nullable; import java.io.File; import java.util.EnumSet; import java.util.List; +@SuppressWarnings("UseOfSystemOutOrSystemErr") abstract class StdLibTestBase extends SingleFileTranslationTest { protected StdLibTestBase() { @@ -37,6 +42,44 @@ abstract class StdLibTestBase extends SingleFileTranslationTest { protected void performStdLibTest(@NotNull EnumSet ecmaVersions, @NotNull String sourceDir, @NotNull String... stdLibFiles) throws Exception { + List files = constructFilesToCompileList(sourceDir, stdLibFiles); + compileFiles(ecmaVersions, files); + } + + private void compileFiles(@NotNull EnumSet ecmaVersions, @NotNull List files) { + List libFiles = createLibFilesList(); + for (EcmaVersion version : ecmaVersions) { + String outputFilePath = getOutputFilePath(getTestName(false) + ".compiler.kt", version); + invokeCompiler(files, libFiles, version, outputFilePath); + } + } + + //TODO: reuse this in CompileMavenGeneratedJSLibrary + private static void invokeCompiler(@NotNull List files, @NotNull List libFiles, + @NotNull EcmaVersion version, @NotNull String outputFilePath) { + K2JSCompiler compiler = new K2JSCompiler(); + K2JSCompilerArguments arguments = new K2JSCompilerArguments(); + arguments.outputFile = outputFilePath; + arguments.sourceFiles = ArrayUtil.toStringArray(files); + arguments.verbose = true; + arguments.libraryFiles = ArrayUtil.toStringArray(libFiles); + System.out.println("Compiling with version: " + version + " to: " + arguments.outputFile); + ExitCode answer = compiler.exec(System.out, arguments); + assertEquals("Compile failed", ExitCode.OK, answer); + } + + @NotNull + private static List createLibFilesList() { + return Lists.transform(Config.LIB_FILE_NAMES, new Function() { + @Override + public String apply(@Nullable String s) { + return Config.LIBRARIES_LOCATION + s; + } + }); + } + + @NotNull + private static List constructFilesToCompileList(@NotNull String sourceDir, @NotNull String[] stdLibFiles) { List files = Lists.newArrayList(); File stdlibDir = new File(sourceDir); @@ -45,7 +88,6 @@ abstract class StdLibTestBase extends SingleFileTranslationTest { files.add(new File(stdlibDir, file).getPath()); } - // lets add the standard JS library files Iterable names = Config.LIB_FILE_NAMES_DEPENDENT_ON_STDLIB; for (String libFileName : names) { @@ -58,9 +100,6 @@ abstract class StdLibTestBase extends SingleFileTranslationTest { System.out.println("Compiling " + libFileName); files.add(Config.STDLIB_LOCATION + libFileName); } - for (EcmaVersion version : ecmaVersions) { - String outputFilePath = getOutputFilePath(getTestName(false) + ".compiler.kt", version); - TranslationUtils.translateFiles(getProject(), files, outputFilePath, MainCallParameters.noCall(), version); - } + return files; } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassAliasingMap.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassAliasingMap.java index c7312044a4b..b38863d4232 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassAliasingMap.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassAliasingMap.java @@ -1,3 +1,19 @@ +/* + * 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.k2js.translate.declaration; import com.google.dart.compiler.backend.js.ast.JsNameRef; diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java index e3a657f5859..4f8b441875f 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java @@ -44,7 +44,7 @@ import org.jetbrains.k2js.translate.expression.WhenTranslator; import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator; import org.jetbrains.k2js.translate.initializer.NamespaceInitializerTranslator; import org.jetbrains.k2js.translate.reference.CallBuilder; -import org.jetbrains.k2js.translate.test.TestGenerator; +import org.jetbrains.k2js.translate.test.JSTestGenerator; import org.jetbrains.k2js.translate.utils.JsAstUtils; import org.jetbrains.k2js.translate.utils.TranslationUtils; import org.jetbrains.k2js.translate.utils.dangerous.DangerousData; @@ -186,7 +186,7 @@ public final class Translation { statements.add(statement); } } - TestGenerator.generateTestCalls(context, files, rootBlock); + JSTestGenerator.generateTestCalls(context, files, rootBlock); performSimpleNameMangling(context.program()); return context.program(); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java index 5389fae9639..c55be86d03a 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java @@ -39,8 +39,8 @@ import static org.jetbrains.k2js.translate.operation.AssignmentTranslator.isAssi import static org.jetbrains.k2js.translate.operation.CompareToTranslator.isCompareToCall; import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall; -import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.isEquals; import static org.jetbrains.k2js.translate.utils.JsAstUtils.not; +import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.isEquals; import static org.jetbrains.k2js.translate.utils.PsiUtils.*; import static org.jetbrains.k2js.translate.utils.TranslationUtils.*; @@ -52,13 +52,13 @@ public final class BinaryOperationTranslator extends AbstractTranslator { @NotNull public static JsExpression translate(@NotNull JetBinaryExpression expression, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { return (new BinaryOperationTranslator(expression, context).translate()); } @NotNull /*package*/ static JsExpression translateAsOverloadedCall(@NotNull JetBinaryExpression expression, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { return (new BinaryOperationTranslator(expression, context)).translateAsOverloadedBinaryOperation(); } @@ -69,11 +69,11 @@ public final class BinaryOperationTranslator extends AbstractTranslator { private final FunctionDescriptor operationDescriptor; private BinaryOperationTranslator(@NotNull JetBinaryExpression expression, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { super(context); this.expression = expression; this.operationDescriptor = - getFunctionDescriptorForOperationExpression(bindingContext(), expression); + getFunctionDescriptorForOperationExpression(bindingContext(), expression); } @NotNull @@ -91,9 +91,9 @@ public final class BinaryOperationTranslator extends AbstractTranslator { return CompareToTranslator.translate(expression, context()); } assert operationDescriptor != null : - "Overloadable operations must have not null descriptor"; - if (isEquals(operationDescriptor)) { - return translateAsEqualsCall(); + "Overloadable operations must have not null descriptor"; + if (isEquals(operationDescriptor) && context().intrinsics().isIntrinsic(operationDescriptor)) { + return translateAsEqualsIntrinsic(); } return translateAsOverloadedBinaryOperation(); } @@ -116,7 +116,7 @@ public final class BinaryOperationTranslator extends AbstractTranslator { } @NotNull - private JsExpression translateAsEqualsCall() { + private JsExpression translateAsEqualsIntrinsic() { assert operationDescriptor != null : "Equals operation must resolve to descriptor."; EqualsIntrinsic intrinsic = context().intrinsics().getEqualsIntrinsic(operationDescriptor); intrinsic.setNegated(expression.getOperationToken().equals(JetTokens.EXCLEQ)); @@ -137,10 +137,8 @@ public final class BinaryOperationTranslator extends AbstractTranslator { @NotNull private JsExpression translateAsOverloadedBinaryOperation() { CallBuilder callBuilder = setReceiverAndArguments(); - ResolvedCall resolvedCall1 = - getResolvedCall(bindingContext(), expression.getOperationReference()); - JsExpression result = callBuilder.resolvedCall(resolvedCall1) - .type(CallType.NORMAL).translate(); + ResolvedCall resolvedCall = getResolvedCall(bindingContext(), expression.getOperationReference()); + JsExpression result = callBuilder.resolvedCall(resolvedCall).type(CallType.NORMAL).translate(); return mayBeWrapWithNegation(result); } @@ -161,7 +159,7 @@ public final class BinaryOperationTranslator extends AbstractTranslator { @NotNull private JsExpression mayBeWrapWithNegation(@NotNull JsExpression result) { - if (isNotInOperation(expression)) { + if (isNegatedOperation(expression)) { return not(result); } else { diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/test/TestGenerator.java b/js/js.translator/src/org/jetbrains/k2js/translate/test/TestGenerator.java deleted file mode 100644 index f2bb3a18c79..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/test/TestGenerator.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.k2js.translate.test; - -import com.google.dart.compiler.backend.js.ast.*; -import com.google.dart.compiler.util.AstUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.general.JetTestFunctionDetector; -import org.jetbrains.k2js.translate.reference.CallBuilder; -import org.jetbrains.k2js.translate.reference.ReferenceTranslator; -import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; - -import java.util.Collection; -import java.util.List; - -import static com.google.dart.compiler.util.AstUtil.newBlock; - -/** - * @author Pavel Talanov - */ -public final class TestGenerator { - private TestGenerator() { - } - - public static void generateTestCalls(@NotNull TranslationContext context, - @NotNull Collection files, - @NotNull JsBlock block) { - List functionDescriptors = JetTestFunctionDetector.getTestFunctionDescriptors(context.bindingContext(), files); - doGenerateTestCalls(functionDescriptors, block, context); - } - - private static void doGenerateTestCalls(@NotNull List functionDescriptors, - @NotNull JsBlock block, - @NotNull TranslationContext context) { - for (FunctionDescriptor functionDescriptor : functionDescriptors) { - ClassDescriptor classDescriptor = JsDescriptorUtils.getContainingClass(functionDescriptor); - if (classDescriptor == null) { - return; - } - JsExpression expression = ReferenceTranslator.translateAsFQReference(classDescriptor, context); - JsNew constructClassExpr = new JsNew(expression); - JsExpression functionToTestCall = - CallBuilder.build(context).descriptor(functionDescriptor).receiver(constructClassExpr).translate(); - JsNameRef qUnitTestFunRef = AstUtil.newQualifiedNameRef("QUnit.test"); - JsFunction functionToTest = new JsFunction(context.jsScope()); - functionToTest.setBody(newBlock(functionToTestCall.makeStmt())); - String testName = classDescriptor.getName() + "." + functionDescriptor.getName(); - block.getStatements() - .add(AstUtil.newInvocation(qUnitTestFunRef, context.program().getStringLiteral(testName), functionToTest) - .makeStmt()); - } - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java index e4f08b3a55a..7aeb7b2882d 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java @@ -93,6 +93,10 @@ public final class PsiUtils { return (binaryExpression.getOperationToken() == JetTokens.NOT_IN); } + public static boolean isNegatedOperation(@NotNull JetBinaryExpression binaryExpression) { + return (binaryExpression.getOperationToken() == JetTokens.EXCLEQ) || isNotInOperation(binaryExpression); + } + private static boolean isInOperation(@NotNull JetBinaryExpression binaryExpression) { return (binaryExpression.getOperationToken() == JetTokens.IN_KEYWORD); } diff --git a/js/js.translator/testFiles/expression/equals/cases/customEqualsMethod.kt b/js/js.translator/testFiles/expression/equals/cases/customEqualsMethod.kt index 70c58bf634f..4dae1afc721 100644 --- a/js/js.translator/testFiles/expression/equals/cases/customEqualsMethod.kt +++ b/js/js.translator/testFiles/expression/equals/cases/customEqualsMethod.kt @@ -1,9 +1,12 @@ package foo class Foo(val name: String) { - public fun equals(that: Foo): Boolean { - return this.name == that.name - } + public fun equals(that: Any?): Boolean { + if (that !is Foo) { + return false + } + return this.name == that.name + } } fun box() : Boolean { diff --git a/js/js.translator/testFiles/kotlin_lib.js b/js/js.translator/testFiles/kotlin_lib.js index eb4954fa902..6521bb8111b 100644 --- a/js/js.translator/testFiles/kotlin_lib.js +++ b/js/js.translator/testFiles/kotlin_lib.js @@ -108,6 +108,39 @@ var kotlin = {set:function (receiver, key, value) { }, contains: function (o) { return this.indexOf(o) != -1; + }, + equals: function (o) { + if (this.$size === o.$size) { + var iter1 = this.iterator(); + var iter2 = o.iterator(); + while (true) { + var hn1 = iter1.get_hasNext(); + var hn2 = iter2.get_hasNext(); + if (hn1 != hn2) return false; + if (!hn2) + return true; + else { + var o1 = iter1.next(); + var o2 = iter2.next(); + if (!Kotlin.equals(o1, o2)) return false; + } + } + } + return false; + }, + toString: function() { + var builder = "["; + var iter = this.iterator(); + var first = true; + while (iter.get_hasNext()) { + if (first) + first = false; + else + builder += ", "; + builder += iter.next(); + } + builder += "]"; + return builder; } });