Browse Source

Set: fix #1225, fix #1226, fix #1227, fix #1228.

Herby Vojčík 4 months ago
parent
commit
57b67fc75c
4 changed files with 152 additions and 15 deletions
  1. 18 11
      lang/src/Kernel-Collections.js
  2. 11 4
      lang/src/Kernel-Collections.st
  3. 107 0
      lang/src/Kernel-Tests.js
  4. 16 0
      lang/src/Kernel-Tests.st

+ 18 - 11
lang/src/Kernel-Collections.js

@@ -8123,7 +8123,7 @@ var self=this,$self=this;
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 
-		if (anObject in anotherObject.store) { return false; }
+		if (anObject in anotherObject.store) { return anObject; }
 		$self['@size']++;
 		anotherObject.store[anObject] = true;
 		return anObject;
@@ -8135,7 +8135,7 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anObject", "anotherObject"],
-source: "add: anObject in: anotherObject\x0a\x09<inlineJS: '\x0a\x09\x09if (anObject in anotherObject.store) { return false; }\x0a\x09\x09$self[''@size'']++;\x0a\x09\x09anotherObject.store[anObject] = true;\x0a\x09\x09return anObject;\x0a\x09'>",
+source: "add: anObject in: anotherObject\x0a\x09<inlineJS: '\x0a\x09\x09if (anObject in anotherObject.store) { return anObject; }\x0a\x09\x09$self[''@size'']++;\x0a\x09\x09anotherObject.store[anObject] = true;\x0a\x09\x09return anObject;\x0a\x09'>",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
@@ -8572,7 +8572,7 @@ return $self["@size"];
 } else {
 var primitiveBucket;
 primitiveBucket=$receiver;
-return $self._remove_in_($recv(bucket)._first(),primitiveBucket);
+return $self._remove_in_ifAbsent_($recv(bucket)._first(),primitiveBucket,aBlock);
 }
 }
 catch(e) {if(e===$early)return e[0]; throw e}
@@ -8582,31 +8582,38 @@ catch(e) {if(e===$early)return e[0]; throw e}
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anObject", "aBlock"],
-source: "remove: anObject ifAbsent: aBlock\x0a\x09| bucket |\x0a\x09bucket := self bucketsOfElement: anObject.\x0a\x09^ bucket second\x0a\x09\x09ifNil: [ bucket third remove: bucket first ifAbsent: [ ^aBlock value ]. size := size - 1 ]\x0a\x09\x09ifNotNil: [ :primitiveBucket | self remove: bucket first in: primitiveBucket ]",
+source: "remove: anObject ifAbsent: aBlock\x0a\x09| bucket |\x0a\x09bucket := self bucketsOfElement: anObject.\x0a\x09^ bucket second\x0a\x09\x09ifNil: [ bucket third remove: bucket first ifAbsent: [ ^aBlock value ]. size := size - 1 ]\x0a\x09\x09ifNotNil: [ :primitiveBucket | self remove: bucket first in: primitiveBucket ifAbsent: aBlock ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["bucketsOfElement:", "ifNil:ifNotNil:", "second", "remove:ifAbsent:", "third", "first", "value", "-", "remove:in:"]
+messageSends: ["bucketsOfElement:", "ifNil:ifNotNil:", "second", "remove:ifAbsent:", "third", "first", "value", "-", "remove:in:ifAbsent:"]
 }),
 $globals.Set);
 
 $core.addMethod(
 $core.method({
-selector: "remove:in:",
+selector: "remove:in:ifAbsent:",
 protocol: "private",
-fn: function (anObject,anotherObject){
+fn: function (anObject,anotherObject,aBlock){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-if (anObject in anotherObject.store) { delete anotherObject.store[anObject]; $self['@size']--; };
+
+		if (anObject in anotherObject.store) {
+			delete anotherObject.store[anObject];
+			$self['@size']--;
+			return anObject;
+		} else {
+			return aBlock._value();
+		};
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"remove:in:",{anObject:anObject,anotherObject:anotherObject},$globals.Set)});
+}, function($ctx1) {$ctx1.fill(self,"remove:in:ifAbsent:",{anObject:anObject,anotherObject:anotherObject,aBlock:aBlock},$globals.Set)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anObject", "anotherObject"],
-source: "remove: anObject in: anotherObject\x0a\x09<inlineJS: 'if (anObject in anotherObject.store) { delete anotherObject.store[anObject]; $self[''@size'']--; }'>",
+args: ["anObject", "anotherObject", "aBlock"],
+source: "remove: anObject in: anotherObject ifAbsent: aBlock\x0a\x09<inlineJS: '\x0a\x09\x09if (anObject in anotherObject.store) {\x0a\x09\x09\x09delete anotherObject.store[anObject];\x0a\x09\x09\x09$self[''@size'']--;\x0a\x09\x09\x09return anObject;\x0a\x09\x09} else {\x0a\x09\x09\x09return aBlock._value();\x0a\x09\x09}'>",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []

+ 11 - 4
lang/src/Kernel-Collections.st

@@ -1937,7 +1937,7 @@ remove: anObject ifAbsent: aBlock
 	bucket := self bucketsOfElement: anObject.
 	^ bucket second
 		ifNil: [ bucket third remove: bucket first ifAbsent: [ ^aBlock value ]. size := size - 1 ]
-		ifNotNil: [ :primitiveBucket | self remove: bucket first in: primitiveBucket ]
+		ifNotNil: [ :primitiveBucket | self remove: bucket first in: primitiveBucket ifAbsent: aBlock ]
 !
 
 removeAll
@@ -2044,7 +2044,7 @@ printOn: aStream
 
 add: anObject in: anotherObject
 	<inlineJS: '
-		if (anObject in anotherObject.store) { return false; }
+		if (anObject in anotherObject.store) { return anObject; }
 		$self[''@size'']++;
 		anotherObject.store[anObject] = true;
 		return anObject;
@@ -2089,8 +2089,15 @@ jsConstructorNameOf: anObject
 	<inlineJS: 'return anObject.constructor && anObject.constructor.name'>
 !
 
-remove: anObject in: anotherObject
-	<inlineJS: 'if (anObject in anotherObject.store) { delete anotherObject.store[anObject]; $self[''@size'']--; }'>
+remove: anObject in: anotherObject ifAbsent: aBlock
+	<inlineJS: '
+		if (anObject in anotherObject.store) {
+			delete anotherObject.store[anObject];
+			$self[''@size'']--;
+			return anObject;
+		} else {
+			return aBlock._value();
+		}'>
 ! !
 
 !Set methodsFor: 'testing'!

+ 107 - 0
lang/src/Kernel-Tests.js

@@ -10081,6 +10081,113 @@ messageSends: ["new", "assert:equals:", "printString", "add:", "remove:"]
 }),
 $globals.SetTest);
 
+$core.addMethod(
+$core.method({
+selector: "testRegression1225",
+protocol: "tests",
+fn: function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._assert_equals_($recv([(1), (2), (3)]._asSet())._add_((3)),(3));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testRegression1225",{},$globals.SetTest)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testRegression1225\x0a\x09self assert: (#(1 2 3) asSet add: 3) equals: 3",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["assert:equals:", "add:", "asSet"]
+}),
+$globals.SetTest);
+
+$core.addMethod(
+$core.method({
+selector: "testRegression1226",
+protocol: "tests",
+fn: function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._assert_equals_($recv([(1), (2), (3)]._asSet())._remove_((3)),(3));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testRegression1226",{},$globals.SetTest)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testRegression1226\x0a\x09self assert: (#(1 2 3) asSet remove: 3) equals: 3",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["assert:equals:", "remove:", "asSet"]
+}),
+$globals.SetTest);
+
+$core.addMethod(
+$core.method({
+selector: "testRegression1227",
+protocol: "tests",
+fn: function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._assert_equals_($recv([(1), (2), (3)]._asSet())._remove_ifAbsent_((4),(function(){
+return (5);
+
+})),(5));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testRegression1227",{},$globals.SetTest)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testRegression1227\x0a\x09self assert: (#(1 2 3) asSet remove: 4 ifAbsent: [5]) equals: 5",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["assert:equals:", "remove:ifAbsent:", "asSet"]
+}),
+$globals.SetTest);
+
+$core.addMethod(
+$core.method({
+selector: "testRegression1228",
+protocol: "tests",
+fn: function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._should_raise_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv([(1), (2), (3)]._asSet())._remove_((4));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}),$globals.Error);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testRegression1228",{},$globals.SetTest)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testRegression1228\x0a\x09self should: [#(1 2 3) asSet remove: 4] raise: Error",
+referencedClasses: ["Error"],
+//>>excludeEnd("ide");
+messageSends: ["should:raise:", "remove:", "asSet"]
+}),
+$globals.SetTest);
+
 $core.addMethod(
 $core.method({
 selector: "testUnboxedObjects",

+ 16 - 0
lang/src/Kernel-Tests.st

@@ -1828,6 +1828,22 @@ testPrintString
 	self assert: set printString equals: 'a Set (3 ''foo'')'
 !
 
+testRegression1225
+	self assert: (#(1 2 3) asSet add: 3) equals: 3
+!
+
+testRegression1226
+	self assert: (#(1 2 3) asSet remove: 3) equals: 3
+!
+
+testRegression1227
+	self assert: (#(1 2 3) asSet remove: 4 ifAbsent: [5]) equals: 5
+!
+
+testRegression1228
+	self should: [#(1 2 3) asSet remove: 4] raise: Error
+!
+
 testUnboxedObjects
 	self assert: {'foo' yourself. 'foo' yourself} asSet asArray equals: #('foo')
 !