From 098b4c170fc86b28b6f3126cb979947223353d54 Mon Sep 17 00:00:00 2001 From: Michael Nedzelsky Date: Mon, 22 Sep 2014 19:14:12 +0400 Subject: [PATCH] JS backend: fix KT-4297 PrimitiveHashMap returns wrong keys (string instead of original type) --- .../test/semantics/StandardClassesTest.java | 8 ++ .../functions/factories/TopLevelFIF.java | 20 +++-- js/js.translator/testData/maps.js | 82 +++++++++++++++++- .../cases/hashMapTypeOfElement.kt | 86 +++++++++++++++++++ .../cases/hashSetTypeOfElement.kt | 74 ++++++++++++++++ 5 files changed, 259 insertions(+), 11 deletions(-) create mode 100644 js/js.translator/testData/standardClasses/cases/hashMapTypeOfElement.kt create mode 100644 js/js.translator/testData/standardClasses/cases/hashSetTypeOfElement.kt diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/StandardClassesTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StandardClassesTest.java index 24f3ea5f355..1d489de4ae1 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/StandardClassesTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StandardClassesTest.java @@ -66,4 +66,12 @@ public final class StandardClassesTest extends SingleFileTranslationTest { public void testStringBuilder() throws Exception { checkFooBoxIsOk(); } + + public void testHashSetTypeOfElement() throws Exception { + checkFooBoxIsOk(); + } + + public void testHashMapTypeOfElement() throws Exception { + checkFooBoxIsOk(); + } } \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java index 7b581850f66..aa0aa7ca17e 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java @@ -232,14 +232,20 @@ public final class TopLevelFIF extends CompositeFIF { ) { JetType keyType = callInfo.getResolvedCall().getTypeArguments().values().iterator().next(); Name keyTypeName = JsDescriptorUtils.getNameIfStandardType(keyType); - String collectionClassName; - if (keyTypeName != null && - (NamePredicate.PRIMITIVE_NUMBERS.apply(keyTypeName) || - keyTypeName.asString().equals("String") || - PrimitiveType.BOOLEAN.getTypeName().equals(keyTypeName))) { - collectionClassName = isSet ? "PrimitiveHashSet" : "PrimitiveHashMap"; + String collectionClassName = null; + if (keyTypeName != null) { + if (NamePredicate.PRIMITIVE_NUMBERS.apply(keyTypeName)) { + collectionClassName = isSet ? "PrimitiveNumberHashSet" : "PrimitiveNumberHashMap"; + } + else if (PrimitiveType.BOOLEAN.getTypeName().equals(keyTypeName)) { + collectionClassName = isSet ? "PrimitiveBooleanHashSet" : "PrimitiveBooleanHashMap"; + } + else if (keyTypeName.asString().equals("String")) { + collectionClassName = isSet ? "DefaultPrimitiveHashSet" : "DefaultPrimitiveHashMap"; + } } - else { + + if (collectionClassName == null ) { collectionClassName = isSet ? "ComplexHashSet" : "ComplexHashMap"; } diff --git a/js/js.translator/testData/maps.js b/js/js.translator/testData/maps.js index 36e78202ff7..0ad237c927c 100644 --- a/js/js.translator/testData/maps.js +++ b/js/js.translator/testData/maps.js @@ -481,7 +481,7 @@ * @constructor * @template Key, Value */ - Kotlin.PrimitiveHashMap = Kotlin.createClassNow(Kotlin.Map, + Kotlin.AbstractPrimitiveHashMap = Kotlin.createClassNow(Kotlin.Map, function () { this.$size = 0; this.map = Object.create(null); @@ -541,8 +541,11 @@ return result; }, + getKeySetClass: function () { + throw new Error("Kotlin.AbstractPrimitiveHashMap.getKetSetClass is abstract"); + }, keySet: function () { - var result = new Kotlin.PrimitiveHashSet(); + var result = new (this.getKeySetClass())(); var map = this.map; for (var key in map) { //noinspection JSUnfilteredForInLoop @@ -559,6 +562,34 @@ } }); + Kotlin.DefaultPrimitiveHashMap = Kotlin.createClassNow(Kotlin.AbstractPrimitiveHashMap, + function () { + Kotlin.AbstractPrimitiveHashMap.call(this); + }, { + getKeySetClass: function () { + return Kotlin.DefaultPrimitiveHashSet; + } + }); + + Kotlin.PrimitiveNumberHashMap = Kotlin.createClassNow(Kotlin.AbstractPrimitiveHashMap, + function () { + Kotlin.AbstractPrimitiveHashMap.call(this); + this.$keySetClass$ = Kotlin.PrimitiveNumberHashSet; + }, { + getKeySetClass: function () { + return Kotlin.PrimitiveNumberHashSet; + } + }); + + Kotlin.PrimitiveBooleanHashMap = Kotlin.createClassNow(Kotlin.AbstractPrimitiveHashMap, + function () { + Kotlin.AbstractPrimitiveHashMap.call(this); + }, { + getKeySetClass: function () { + return Kotlin.PrimitiveBooleanHashSet; + } + }); + function LinkedHashMap() { Kotlin.ComplexHashMap.call(this); this.orderedKeys = []; @@ -688,13 +719,13 @@ var SetIterator = Kotlin.createClassNow(Kotlin.Iterator, * @extends {Kotlin.Collection.} * @template T */ -Kotlin.PrimitiveHashSet = Kotlin.createClassNow(Kotlin.AbstractCollection, +Kotlin.AbstractPrimitiveHashSet = Kotlin.createClassNow(Kotlin.AbstractCollection, /** @constructs */ function () { this.$size = 0; this.map = {}; }, - /** @lends {Kotlin.PrimitiveHashSet.prototype} */ + /** @lends {Kotlin.AbstractPrimitiveHashSet.prototype} */ { size: function () { return this.$size; @@ -730,11 +761,54 @@ Kotlin.PrimitiveHashSet = Kotlin.createClassNow(Kotlin.AbstractCollection, this.$size = 0; this.map = {}; }, + convertKeyToKeyType: function (key) { + throw new Error("Kotlin.AbstractPrimitiveHashSet.convertKeyToKeyType is abstract"); + }, + toArray: function () { + var result = Object.keys(this.map); + for(var i=0; i() + mapWithIntKeys[1] = 1 + assertEquals("number", typeof (mapWithIntKeys.keySet().iterator().next()), "mapWithIntKeys") + + val mapWithShortKeys = HashMap() + mapWithShortKeys[1: Short] = 1 + assertEquals("number", typeof (mapWithShortKeys.keySet().iterator().next()), "mapWithShortKeys") + + val mapWithByteKeys = HashMap() + mapWithByteKeys[1: Byte] = 1 + assertEquals("number", typeof (mapWithByteKeys.keySet().iterator().next()), "mapWithByteKeys") + + val mapWithDoubleKeys = HashMap() + mapWithDoubleKeys[1.0] = 1 + assertEquals("number", typeof (mapWithDoubleKeys.keySet().iterator().next()), "mapWithDoubleKeys") + + mapWithDoubleKeys.clear() + var dNaN = 0.0 / 0.0 + mapWithDoubleKeys[dNaN] = 100 + assertEquals(100, mapWithDoubleKeys[dNaN]) + assertEquals("number", typeof (mapWithDoubleKeys.keySet().iterator().next()), "dNaN") + + mapWithDoubleKeys.clear() + var dPositiveInfinity = +1.0 / 0.0 + mapWithDoubleKeys[dPositiveInfinity] = 100 + assertEquals(100, mapWithDoubleKeys[dPositiveInfinity]) + assertEquals("number", typeof (mapWithDoubleKeys.keySet().iterator().next()), "dPositiveInfinity") + + mapWithDoubleKeys.clear() + var dNegativeInfinity = -1.0 / 0.0 + mapWithDoubleKeys[dNegativeInfinity] = 100 + assertEquals(100, mapWithDoubleKeys[dNegativeInfinity]) + assertEquals("number", typeof (mapWithDoubleKeys.keySet().iterator().next()), "dNegativeInfinity") + + val mapWithFloatKeys = HashMap() + mapWithFloatKeys[1.0f] = 1 + assertEquals("number", typeof (mapWithFloatKeys.keySet().iterator().next()), "mapWithFloatKeys") + + mapWithFloatKeys.clear() + var fNaN: Float = 0.0f / 0.0f + mapWithFloatKeys[dNaN] = 100 + assertEquals(100, mapWithFloatKeys[dNaN]) + assertEquals("number", typeof (mapWithFloatKeys.keySet().iterator().next()), "fNaN") + + mapWithFloatKeys.clear() + var fPositiveInfinity = +1.0f / 0.0f + mapWithFloatKeys[fPositiveInfinity] = 100 + assertEquals(100, mapWithFloatKeys[fPositiveInfinity]) + assertEquals("number", typeof (mapWithFloatKeys.keySet().iterator().next()), "fPositiveInfinity") + + mapWithFloatKeys.clear() + var NegativeInfinity = -1.0f / 0.0f + mapWithFloatKeys[NegativeInfinity] = 100 + assertEquals(100, mapWithFloatKeys[NegativeInfinity]) + assertEquals("number", typeof (mapWithFloatKeys.keySet().iterator().next()), "fNegativeInfinity") + + val mapWithCharKeys = HashMap() + mapWithCharKeys['A'] = 1 + assertEquals("number", typeof (mapWithCharKeys.keySet().iterator().next()), "mapWithCharKeys") + + val mapWithLongKeys = HashMap() + mapWithLongKeys[1L] = 1 + assertEquals("number", typeof (mapWithLongKeys.keySet().iterator().next()), "mapWithLongKeys") + + val mapWithBooleanKeys = HashMap() + mapWithBooleanKeys[true] = 1 + assertEquals("boolean", typeof (mapWithBooleanKeys.keySet().iterator().next()), "mapWithBooleanKeys") + + val mapWithStringKeys = HashMap() + mapWithStringKeys["key"] = 1 + assertEquals("string", typeof (mapWithStringKeys.keySet().iterator().next()), "mapWithStringKeys") + + return "OK" +} + diff --git a/js/js.translator/testData/standardClasses/cases/hashSetTypeOfElement.kt b/js/js.translator/testData/standardClasses/cases/hashSetTypeOfElement.kt new file mode 100644 index 00000000000..ff1f87e7642 --- /dev/null +++ b/js/js.translator/testData/standardClasses/cases/hashSetTypeOfElement.kt @@ -0,0 +1,74 @@ +package foo + +import java.util.HashSet + +native fun typeof(a: Any): String = noImpl + +fun box(): String { + + val x = true + val y = false + + val intSet = HashSet() + intSet.add(1) + assertEquals("number", typeof (intSet.iterator().next()), "intSet") + + val shortSet = HashSet() + shortSet.add(1: Short) + assertEquals("number", typeof (shortSet.iterator().next()), "shortSet") + + val byteSet = HashSet() + byteSet.add(1: Byte) + assertEquals("number", typeof (byteSet.iterator().next()), "byteSet") + + val doubleSet = HashSet() + doubleSet.add(1.0) + assertEquals("number", typeof (doubleSet.iterator().next()), "doubleSet") + + doubleSet.clear() + doubleSet.add(0.0 / 0.0) + assertEquals("number", typeof (doubleSet.iterator().next()), "dNaN") + + doubleSet.clear() + doubleSet.add(1.0 / 0.0) + assertEquals("number", typeof (doubleSet.iterator().next()), "dPositiveInfinity") + + doubleSet.clear() + doubleSet.add(-1.0 / 0.0) + assertEquals("number", typeof (doubleSet.iterator().next()), "dNegativeInfinity") + + val floatSet = HashSet() + floatSet.add(1.0f) + assertEquals("number", typeof (floatSet.iterator().next()), "floatSet") + + floatSet.clear() + floatSet.add(0.0f / 0.0f) + assertEquals("number", typeof (floatSet.iterator().next()), "fNaN") + + floatSet.clear() + floatSet.add(+1.0f / 0.0f) + assertEquals("number", typeof (floatSet.iterator().next()), "fPositiveInfinity") + + floatSet.clear() + floatSet.add(-1.0f / 0.0f) + assertEquals("number", typeof (floatSet.iterator().next()), "fNegativeInfinity") + + val charSet = HashSet() + charSet.add('A') + assertEquals("number", typeof (charSet.iterator().next()), "charSet") + + val longSet = HashSet() + longSet.add(1L) + assertEquals("number", typeof (longSet.iterator().next()), "longSet") + + val booleanSet = HashSet() + booleanSet.add(true) + assertEquals("boolean", typeof (booleanSet.iterator().next()), "booleanSet") + + val stringSet = HashSet() + stringSet.add("text") + assertEquals("string", typeof (stringSet.iterator().next()), "stringSet") + + return "OK" +} +