6 Commits c589128375 ... 2651404497

Author SHA1 Message Date
  Herby Vojčík 2651404497 Local-return-aware `Promise new:`. Fixes #1257. 3 years ago
  Herby Vojčík 689851bad8 SUnit fix for promises rejected with non-Errors. 3 years ago
  Herby Vojčík 7a1336ff55 Promise tests. 3 years ago
  Herby Vojčík 1b25dc062b Clean uses of #messageText:. 3 years ago
  Herby Vojčík c65b7dcda0 Stop using tryCatch:. 3 years ago
  Herby Vojčík ead783ab1d PromiseExecution reified. 3 years ago

+ 8 - 0
CHANGELOG

@@ -1,3 +1,11 @@
+?? Oct 2020 - Release 0.29.6
+===================================
+
+* A model in `Promise new: [ :model | ... ]` reified as PromiseExecution.
+
+Commits: https://lolg.it/amber/amber/commits/0.29.6.
+
+
 7 Oct 2020 - Release 0.29.5
 7 Oct 2020 - Release 0.29.5
 ===================================
 ===================================
 
 

+ 19 - 0
lang/API-CHANGES.txt

@@ -1,3 +1,22 @@
+0.29.6:
+
+* Add TPromiseModel with unary value / signal passing to 1-arg.
+  * Promise class as well as PromiseExecution use it.
+
++ Error class >>
+  + messageText:
++ PromiseExecution >>
+  + do:
+  + signal:
+  + try:
+  + value:
++ TPromiseModel >>
+  + signal
+  + signal:
+  + value
+  + value:
+
+
 0.29.5:
 0.29.5:
 
 
 + (model in `Promise new: [ :model | ]`) >>
 + (model in `Promise new: [ :model | ]`) >>

+ 18 - 19
lang/src/Compiler-Core.js

@@ -911,11 +911,11 @@ selector: "parse:",
 protocol: "compiling",
 protocol: "compiling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString"],
 args: ["aString"],
-source: "parse: aString\x0a\x09| result |\x0a\x09\x0a\x09[ result := self basicParse: aString ] \x0a\x09\x09tryCatch: [ :ex | (self parseError: ex parsing: aString) signal ].\x0a\x09\x09\x0a\x09^ result",
+source: "parse: aString\x0a\x09| result |\x0a\x09\x0a\x09[ result := self basicParse: aString ] \x0a\x09\x09tryIfTrue: [ :err | (err basicAt: 'location') notNil ]\x0a\x09\x09catch: [ :ex | (self parseError: ex parsing: aString) signal ].\x0a\x09\x09\x0a\x09^ result",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["tryCatch:", "basicParse:", "signal", "parseError:parsing:"]
+messageSends: ["tryIfTrue:catch:", "basicParse:", "notNil", "basicAt:", "signal", "parseError:parsing:"]
 }, function ($methodClass){ return function (aString){
 }, function ($methodClass){ return function (aString){
 var self=this,$self=this;
 var self=this,$self=this;
 var result;
 var result;
@@ -931,13 +931,21 @@ return result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-}))._tryCatch_((function(ex){
+}))._tryIfTrue_catch_((function(err){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv($recv(err)._basicAt_("location"))._notNil();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({err:err},$ctx1,2)});
+//>>excludeEnd("ctx");
+}),(function(ex){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 return $recv($self._parseError_parsing_(ex,aString))._signal();
 return $recv($self._parseError_parsing_(ex,aString))._signal();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)});
+}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,3)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }));
 }));
 return result;
 return result;
@@ -953,29 +961,23 @@ selector: "parseError:parsing:",
 protocol: "error handling",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anException", "aString"],
 args: ["anException", "aString"],
-source: "parseError: anException parsing: aString\x0a\x09(anException basicAt: 'location')\x0a\x09\x09ifNil: [ ^ anException pass ]\x0a\x09\x09ifNotNil: [ :loc |\x0a\x09\x09\x09^ ParseError new \x0a\x09\x09\x09\x09messageText: \x0a\x09\x09\x09\x09\x09'Parse error on line ', loc start line asString,\x0a\x09\x09\x09\x09\x09' column ' , loc start column asString,\x0a\x09\x09\x09\x09\x09' : Unexpected character ', (anException basicAt: 'found');\x0a\x09\x09\x09\x09yourself ]",
+source: "parseError: anException parsing: aString\x0a\x09| loc |\x0a\x09loc := anException basicAt: 'location'.\x0a\x09^ ParseError messageText:\x0a\x09\x09'Parse error on line ', loc start line asString,\x0a\x09\x09' column ' , loc start column asString,\x0a\x09\x09' : Unexpected character ', (anException basicAt: 'found')",
 referencedClasses: ["ParseError"],
 referencedClasses: ["ParseError"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["ifNil:ifNotNil:", "basicAt:", "pass", "messageText:", "new", ",", "asString", "line", "start", "column", "yourself"]
+messageSends: ["basicAt:", "messageText:", ",", "asString", "line", "start", "column"]
 }, function ($methodClass){ return function (anException,aString){
 }, function ($methodClass){ return function (anException,aString){
 var self=this,$self=this;
 var self=this,$self=this;
+var loc;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1,$2;
-$1=[$recv(anException)._basicAt_("location")
+loc=[$recv(anException)._basicAt_("location")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 ,$ctx1.sendIdx["basicAt:"]=1
 ,$ctx1.sendIdx["basicAt:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 ][0];
 ][0];
-if($1 == null || $1.a$nil){
-return $recv(anException)._pass();
-} else {
-var loc;
-loc=$1;
-$2=$recv($globals.ParseError)._new();
-$recv($2)._messageText_([$recv([$recv([$recv([$recv("Parse error on line ".__comma([$recv($recv([$recv(loc)._start()
+return $recv($globals.ParseError)._messageText_([$recv([$recv([$recv([$recv("Parse error on line ".__comma([$recv($recv([$recv(loc)._start()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 ,$ctx1.sendIdx["start"]=1
 ,$ctx1.sendIdx["start"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -1000,11 +1002,8 @@ $recv($2)._messageText_([$recv([$recv([$recv([$recv("Parse error on line ".__com
 ,$ctx1.sendIdx[","]=1
 ,$ctx1.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 ][0]);
 ][0]);
-return $recv($2)._yourself();
-}
-return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"parseError:parsing:",{anException:anException,aString:aString})});
+}, function($ctx1) {$ctx1.fill(self,"parseError:parsing:",{anException:anException,aString:aString,loc:loc})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }; }),
 }; }),
 $globals.Compiler);
 $globals.Compiler);

+ 8 - 10
lang/src/Compiler-Core.st

@@ -233,7 +233,8 @@ parse: aString
 	| result |
 	| result |
 	
 	
 	[ result := self basicParse: aString ] 
 	[ result := self basicParse: aString ] 
-		tryCatch: [ :ex | (self parseError: ex parsing: aString) signal ].
+		tryIfTrue: [ :err | (err basicAt: 'location') notNil ]
+		catch: [ :ex | (self parseError: ex parsing: aString) signal ].
 		
 		
 	^ result
 	^ result
 !
 !
@@ -286,15 +287,12 @@ error: aString
 !
 !
 
 
 parseError: anException parsing: aString
 parseError: anException parsing: aString
-	(anException basicAt: 'location')
-		ifNil: [ ^ anException pass ]
-		ifNotNil: [ :loc |
-			^ ParseError new 
-				messageText: 
-					'Parse error on line ', loc start line asString,
-					' column ' , loc start column asString,
-					' : Unexpected character ', (anException basicAt: 'found');
-				yourself ]
+	| loc |
+	loc := anException basicAt: 'location'.
+	^ ParseError messageText:
+		'Parse error on line ', loc start line asString,
+		' column ' , loc start column asString,
+		' : Unexpected character ', (anException basicAt: 'found')
 ! !
 ! !
 
 
 !Compiler methodsFor: 'private'!
 !Compiler methodsFor: 'private'!

+ 24 - 0
lang/src/Compiler-Tests.js

@@ -1062,6 +1062,30 @@ return self;
 }; }),
 }; }),
 $globals.AbstractCompilerTest);
 $globals.AbstractCompilerTest);
 
 
+$core.addMethod(
+$core.method({
+selector: "testPromiseWithAsyncExecutorAndLocalReturn",
+protocol: "tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseWithAsyncExecutorAndLocalReturn\x0a\x09self\x0a\x09\x09should: 'foo ^ Promise new: [ :m | [ 3 + 4 ] fork. ^ 5 ]'\x0a\x09\x09return: 5",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["should:return:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._should_return_("foo ^ Promise new: [ :m | [ 3 + 4 ] fork. ^ 5 ]",(5));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseWithAsyncExecutorAndLocalReturn",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.AbstractCompilerTest);
+
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "testReceiverEvaluatedOnceInSpecials",
 selector: "testReceiverEvaluatedOnceInSpecials",

+ 6 - 0
lang/src/Compiler-Tests.st

@@ -245,6 +245,12 @@ testPragmaJSStatement
 	self should: 'foo < inlineJS: ''return 2+3'' >' return: 5
 	self should: 'foo < inlineJS: ''return 2+3'' >' return: 5
 !
 !
 
 
+testPromiseWithAsyncExecutorAndLocalReturn
+	self
+		should: 'foo ^ Promise new: [ :m | [ 3 + 4 ] fork. ^ 5 ]'
+		return: 5
+!
+
 testReceiverEvaluatedOnceInSpecials
 testReceiverEvaluatedOnceInSpecials
 	self should: 'foo |x| x := 1. ^ {[ x := x+1 ] value ifNil: []. x}' return: {2. 2}.
 	self should: 'foo |x| x := 1. ^ {[ x := x+1 ] value ifNil: []. x}' return: {2. 2}.
 	self should: 'foo |xs| xs := {nil. nil}. ^ {[ xs removeLast ] value ifNotNil: []. xs}' return: {nil. {nil}}.
 	self should: 'foo |xs| xs := {nil. nil}. ^ {[ xs removeLast ] value ifNotNil: []. xs}' return: {nil. {nil}}.

+ 27 - 1
lang/src/Kernel-Exceptions.js

@@ -113,7 +113,7 @@ selector: "initialize",
 protocol: "initialization",
 protocol: "initialization",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
 args: [],
-source: "initialize\x0a\x09self messageText: 'Errorclass: ', (self class name).",
+source: "initialize\x0a\x09self messageText: 'Errorclass: ', self class name.",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
@@ -437,6 +437,32 @@ return "exception";
 }; }),
 }; }),
 $globals.Error.a$cls);
 $globals.Error.a$cls);
 
 
+$core.addMethod(
+$core.method({
+selector: "messageText:",
+protocol: "instance creation",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aString"],
+source: "messageText: aString\x0a\x09^ self new\x0a\x09\x09messageText: aString;\x0a\x09\x09yourself",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["messageText:", "new", "yourself"]
+}, function ($methodClass){ return function (aString){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$1=$self._new();
+$recv($1)._messageText_(aString);
+return $recv($1)._yourself();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"messageText:",{aString:aString})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Error.a$cls);
+
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "signal",
 selector: "signal",

+ 7 - 1
lang/src/Kernel-Exceptions.st

@@ -58,7 +58,7 @@ signalerContextFrom: aContext
 !Error methodsFor: 'initialization'!
 !Error methodsFor: 'initialization'!
 
 
 initialize
 initialize
-	self messageText: 'Errorclass: ', (self class name).
+	self messageText: 'Errorclass: ', self class name.
 ! !
 ! !
 
 
 !Error methodsFor: 'private'!
 !Error methodsFor: 'private'!
@@ -116,6 +116,12 @@ classTag
 
 
 !Error class methodsFor: 'instance creation'!
 !Error class methodsFor: 'instance creation'!
 
 
+messageText: aString
+	^ self new
+		messageText: aString;
+		yourself
+!
+
 signal
 signal
 	^ self new signal
 	^ self new signal
 !
 !

+ 1 - 1
lang/src/Kernel-Methods.js

@@ -458,7 +458,7 @@ selector: "tryCatch:",
 protocol: "error handling",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aBlock"],
 args: ["aBlock"],
-source: "tryCatch: aBlock\x0a\x09<inlineJS: '\x0a\x09\x09try {\x0a\x09\x09\x09return $self._value();\x0a\x09\x09} catch(error) {\x0a\x09\x09\x09// pass non-local returns undetected\x0a\x09\x09\x09if (Array.isArray(error) && error.length === 1) throw error;\x0a\x09\x09\x09return aBlock._value_(error);\x0a\x09\x09}\x0a\x09'>",
+source: "tryCatch: aBlock\x0a\x09\x22Too low-level. Try more high-level alternatives like:\x0a\x09\x09[ ... ] on: Error do: [ ... ]\x0a\x09\x09Smalltalk try: [ ... ] ifTrue: [ ... ] catch: [ ... ]\x0a\x09\x09[ ... ] tryIfTrue: [ ... ] catch: [ ... ]\x22\x0a\x09<inlineJS: '\x0a\x09\x09try {\x0a\x09\x09\x09return $self._value();\x0a\x09\x09} catch(error) {\x0a\x09\x09\x09// pass non-local returns undetected\x0a\x09\x09\x09if (Array.isArray(error) && error.length === 1) throw error;\x0a\x09\x09\x09return aBlock._value_(error);\x0a\x09\x09}\x0a\x09'>",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [["inlineJS:", ["\x0a\x09\x09try {\x0a\x09\x09\x09return $self._value();\x0a\x09\x09} catch(error) {\x0a\x09\x09\x09// pass non-local returns undetected\x0a\x09\x09\x09if (Array.isArray(error) && error.length === 1) throw error;\x0a\x09\x09\x09return aBlock._value_(error);\x0a\x09\x09}\x0a\x09"]]],
 pragmas: [["inlineJS:", ["\x0a\x09\x09try {\x0a\x09\x09\x09return $self._value();\x0a\x09\x09} catch(error) {\x0a\x09\x09\x09// pass non-local returns undetected\x0a\x09\x09\x09if (Array.isArray(error) && error.length === 1) throw error;\x0a\x09\x09\x09return aBlock._value_(error);\x0a\x09\x09}\x0a\x09"]]],

+ 4 - 0
lang/src/Kernel-Methods.st

@@ -107,6 +107,10 @@ on: anErrorClass do: aBlock
 !
 !
 
 
 tryCatch: aBlock
 tryCatch: aBlock
+	"Too low-level. Try more high-level alternatives like:
+		[ ... ] on: Error do: [ ... ]
+		Smalltalk try: [ ... ] ifTrue: [ ... ] catch: [ ... ]
+		[ ... ] tryIfTrue: [ ... ] catch: [ ... ]"
 	<inlineJS: '
 	<inlineJS: '
 		try {
 		try {
 			return $self._value();
 			return $self._value();

+ 273 - 14
lang/src/Kernel-Promises.js

@@ -145,28 +145,27 @@ selector: "new:",
 protocol: "instance creation",
 protocol: "instance creation",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aBlock"],
 args: ["aBlock"],
-source: "new: aBlock\x0a\x22Returns a Promise that is eventually resolved or rejected.\x0aPass a block that is called with one argument, model.\x0aYou should call model value: ... to resolve the promise\x0aand model signal: ... to reject the promise.\x0aIf error happens during run of the block,\x0apromise is rejected with that error as well.\x22\x0a<inlineJS: 'return new Promise(function (resolve, reject) {\x0a    var model = {\x0a\x09\x09value: resolve,\x0a\x09\x09signal: reject,\x0a\x09\x09do: function (aBlock) { resolve(this.try(aBlock)); },\x0a\x09\x09try: function (aBlock) {\x0a\x09\x09\x09try { return aBlock._value(); }\x0a\x09\x09\x09catch (e) { reject(e); }\x0a\x09\x09}\x0a\x09};\x0a    aBlock._value_(model);\x0a})'>",
+source: "new: aBlock\x0a\x22Returns a Promise that is eventually resolved or rejected.\x0aPass a block that is called with one argument, model.\x0aYou should call model value: ... to resolve the promise\x0aand model signal: ... to reject the promise.\x0aIf error happens during run of the block,\x0apromise is rejected with that error as well.\x22\x0a<inlineJS: '\x0a\x09var localReturn = null,\x0a\x09\x09promise = new Promise(function (resolve, reject) {\x0a\x09\x09    var model = $globals.PromiseExecution._resolveBlock_rejectBlock_(resolve, reject);\x0a\x09\x09    try { aBlock._value_(model); }\x0a\x09\x09\x09catch (ex) {\x0a\x09\x09\x09\x09if (Array.isArray(ex) && ex.length === 1) localReturn = ex;\x0a\x09\x09\x09\x09else reject(ex);\x0a\x09\x09\x09}\x0a\x09\x09});\x0a\x09if (localReturn) throw localReturn; else return promise;\x0a'>",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
-pragmas: [["inlineJS:", ["return new Promise(function (resolve, reject) {\x0a    var model = {\x0a\x09\x09value: resolve,\x0a\x09\x09signal: reject,\x0a\x09\x09do: function (aBlock) { resolve(this.try(aBlock)); },\x0a\x09\x09try: function (aBlock) {\x0a\x09\x09\x09try { return aBlock._value(); }\x0a\x09\x09\x09catch (e) { reject(e); }\x0a\x09\x09}\x0a\x09};\x0a    aBlock._value_(model);\x0a})"]]],
+pragmas: [["inlineJS:", ["\x0a\x09var localReturn = null,\x0a\x09\x09promise = new Promise(function (resolve, reject) {\x0a\x09\x09    var model = $globals.PromiseExecution._resolveBlock_rejectBlock_(resolve, reject);\x0a\x09\x09    try { aBlock._value_(model); }\x0a\x09\x09\x09catch (ex) {\x0a\x09\x09\x09\x09if (Array.isArray(ex) && ex.length === 1) localReturn = ex;\x0a\x09\x09\x09\x09else reject(ex);\x0a\x09\x09\x09}\x0a\x09\x09});\x0a\x09if (localReturn) throw localReturn; else return promise;"]]],
 messageSends: []
 messageSends: []
 }, function ($methodClass){ return function (aBlock){
 }, function ($methodClass){ return function (aBlock){
 var self=this,$self=this;
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return new Promise(function (resolve, reject) {
-    var model = {
-		value: resolve,
-		signal: reject,
-		do: function (aBlock) { resolve(this.try(aBlock)); },
-		try: function (aBlock) {
-			try { return aBlock._value(); }
-			catch (e) { reject(e); }
-		}
-	};
-    aBlock._value_(model);
-});
+
+	var localReturn = null,
+		promise = new Promise(function (resolve, reject) {
+		    var model = $globals.PromiseExecution._resolveBlock_rejectBlock_(resolve, reject);
+		    try { aBlock._value_(model); }
+			catch (ex) {
+				if (Array.isArray(ex) && ex.length === 1) localReturn = ex;
+				else reject(ex);
+			}
+		});
+	if (localReturn) throw localReturn; else return promise;;
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"new:",{aBlock:aBlock})});
 }, function($ctx1) {$ctx1.fill(self,"new:",{aBlock:aBlock})});
@@ -223,6 +222,264 @@ return self;
 $globals.Promise.a$cls);
 $globals.Promise.a$cls);
 
 
 
 
+$core.addClass("PromiseExecution", $globals.Object, "Kernel-Promises");
+$core.setSlots($globals.PromiseExecution, ["resolveBlock", "rejectBlock"]);
+$core.addMethod(
+$core.method({
+selector: "do:",
+protocol: "evaluating",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aBlock"],
+source: "do: aBlock\x0a\x09self value: (self try: aBlock)",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["value:", "try:"]
+}, function ($methodClass){ return function (aBlock){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._value_($self._try_(aBlock));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"do:",{aBlock:aBlock})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseExecution);
+
+$core.addMethod(
+$core.method({
+selector: "resolveBlock:rejectBlock:",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aBlock", "anotherBlock"],
+source: "resolveBlock: aBlock rejectBlock: anotherBlock\x0a\x09resolveBlock := aBlock.\x0a\x09rejectBlock := anotherBlock",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (aBlock,anotherBlock){
+var self=this,$self=this;
+$self.resolveBlock=aBlock;
+$self.rejectBlock=anotherBlock;
+return self;
+
+}; }),
+$globals.PromiseExecution);
+
+$core.addMethod(
+$core.method({
+selector: "signal:",
+protocol: "settling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anErrorObject"],
+source: "signal: anErrorObject\x0a\x09rejectBlock value: anErrorObject",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["value:"]
+}, function ($methodClass){ return function (anErrorObject){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv($self.rejectBlock)._value_(anErrorObject);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"signal:",{anErrorObject:anErrorObject})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseExecution);
+
+$core.addMethod(
+$core.method({
+selector: "try:",
+protocol: "evaluating",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aBlock"],
+source: "try: aBlock\x0a\x09<inlineJS: '\x0a\x09\x09try {\x0a\x09\x09\x09return aBlock._value();\x0a\x09\x09} catch(error) {\x0a\x09\x09\x09// pass non-local returns undetected\x0a\x09\x09\x09if (Array.isArray(error) && error.length === 1) throw error;\x0a\x09\x09\x09self._signal_(error);\x0a\x09\x09}\x0a\x09'>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [["inlineJS:", ["\x0a\x09\x09try {\x0a\x09\x09\x09return aBlock._value();\x0a\x09\x09} catch(error) {\x0a\x09\x09\x09// pass non-local returns undetected\x0a\x09\x09\x09if (Array.isArray(error) && error.length === 1) throw error;\x0a\x09\x09\x09self._signal_(error);\x0a\x09\x09}\x0a\x09"]]],
+messageSends: []
+}, function ($methodClass){ return function (aBlock){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+
+		try {
+			return aBlock._value();
+		} catch(error) {
+			// pass non-local returns undetected
+			if (Array.isArray(error) && error.length === 1) throw error;
+			self._signal_(error);
+		}
+	;
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"try:",{aBlock:aBlock})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseExecution);
+
+$core.addMethod(
+$core.method({
+selector: "value:",
+protocol: "settling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anObject"],
+source: "value: anObject\x0a\x09resolveBlock value: anObject",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["value:"]
+}, function ($methodClass){ return function (anObject){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv($self.resolveBlock)._value_(anObject);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"value:",{anObject:anObject})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseExecution);
+
+
+$core.addMethod(
+$core.method({
+selector: "resolveBlock:rejectBlock:",
+protocol: "instance creation",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aBlock", "anotherBlock"],
+source: "resolveBlock: aBlock rejectBlock: anotherBlock\x0a\x09^ super new\x0a\x09\x09resolveBlock: aBlock rejectBlock: anotherBlock;\x0a\x09\x09yourself",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["resolveBlock:rejectBlock:", "new", "yourself"]
+}, function ($methodClass){ return function (aBlock,anotherBlock){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$1=[(
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.supercall = true,
+//>>excludeEnd("ctx");
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._new.call($self))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
+$recv($1)._resolveBlock_rejectBlock_(aBlock,anotherBlock);
+return $recv($1)._yourself();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"resolveBlock:rejectBlock:",{aBlock:aBlock,anotherBlock:anotherBlock})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseExecution.a$cls);
+
+
+$core.addTrait("TPromiseModel", "Kernel-Promises");
+$core.addMethod(
+$core.method({
+selector: "signal",
+protocol: "settling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "signal\x0a\x09^ self signal: Error new",
+referencedClasses: ["Error"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["signal:", "new"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $self._signal_($recv($globals.Error)._new());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"signal",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TPromiseModel);
+
+$core.addMethod(
+$core.method({
+selector: "signal:",
+protocol: "settling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anErrorObject"],
+source: "signal: anErrorObject\x0a\x09self subclassResponsibility",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["subclassResponsibility"]
+}, function ($methodClass){ return function (anErrorObject){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._subclassResponsibility();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"signal:",{anErrorObject:anErrorObject})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TPromiseModel);
+
+$core.addMethod(
+$core.method({
+selector: "value",
+protocol: "settling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "value\x0a\x09^ self value: nil",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["value:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $self._value_(nil);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"value",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TPromiseModel);
+
+$core.addMethod(
+$core.method({
+selector: "value:",
+protocol: "settling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anObject"],
+source: "value: anObject\x0a\x09self subclassResponsibility",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["subclassResponsibility"]
+}, function ($methodClass){ return function (anObject){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._subclassResponsibility();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"value:",{anObject:anObject})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TPromiseModel);
+
+
 $core.addTrait("TThenable", "Kernel-Promises");
 $core.addTrait("TThenable", "Kernel-Promises");
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
@@ -425,5 +682,7 @@ return $recv($recv($self._then_(aBlockOrArray))._on_do_(aClass,aBlock))._catch_(
 $globals.TThenable);
 $globals.TThenable);
 
 
 $core.setTraitComposition([{trait: $globals.TThenable}], $globals.Promise);
 $core.setTraitComposition([{trait: $globals.TThenable}], $globals.Promise);
+$core.setTraitComposition([{trait: $globals.TPromiseModel}], $globals.Promise.a$cls);
+$core.setTraitComposition([{trait: $globals.TPromiseModel}], $globals.PromiseExecution);
 
 
 });
 });

+ 82 - 12
lang/src/Kernel-Promises.st

@@ -39,18 +39,18 @@ You should call model value: ... to resolve the promise
 and model signal: ... to reject the promise.
 and model signal: ... to reject the promise.
 If error happens during run of the block,
 If error happens during run of the block,
 promise is rejected with that error as well."
 promise is rejected with that error as well."
-<inlineJS: 'return new Promise(function (resolve, reject) {
-    var model = {
-		value: resolve,
-		signal: reject,
-		do: function (aBlock) { resolve(this.try(aBlock)); },
-		try: function (aBlock) {
-			try { return aBlock._value(); }
-			catch (e) { reject(e); }
-		}
-	};
-    aBlock._value_(model);
-})'>
+<inlineJS: '
+	var localReturn = null,
+		promise = new Promise(function (resolve, reject) {
+		    var model = $globals.PromiseExecution._resolveBlock_rejectBlock_(resolve, reject);
+		    try { aBlock._value_(model); }
+			catch (ex) {
+				if (Array.isArray(ex) && ex.length === 1) localReturn = ex;
+				else reject(ex);
+			}
+		});
+	if (localReturn) throw localReturn; else return promise;
+'>
 !
 !
 
 
 signal: anObject
 signal: anObject
@@ -63,6 +63,74 @@ value: anObject
 <inlineJS: 'return $recv(anObject)._in_(function (x) {return Promise.resolve(x)})'>
 <inlineJS: 'return $recv(anObject)._in_(function (x) {return Promise.resolve(x)})'>
 ! !
 ! !
 
 
+Object subclass: #PromiseExecution
+	slots: {#resolveBlock. #rejectBlock}
+	package: 'Kernel-Promises'!
+
+!PromiseExecution methodsFor: 'accessing'!
+
+resolveBlock: aBlock rejectBlock: anotherBlock
+	resolveBlock := aBlock.
+	rejectBlock := anotherBlock
+! !
+
+!PromiseExecution methodsFor: 'evaluating'!
+
+do: aBlock
+	self value: (self try: aBlock)
+!
+
+try: aBlock
+	<inlineJS: '
+		try {
+			return aBlock._value();
+		} catch(error) {
+			// pass non-local returns undetected
+			if (Array.isArray(error) && error.length === 1) throw error;
+			self._signal_(error);
+		}
+	'>
+! !
+
+!PromiseExecution methodsFor: 'settling'!
+
+signal: anErrorObject
+	rejectBlock value: anErrorObject
+!
+
+value: anObject
+	resolveBlock value: anObject
+! !
+
+!PromiseExecution class methodsFor: 'instance creation'!
+
+resolveBlock: aBlock rejectBlock: anotherBlock
+	^ super new
+		resolveBlock: aBlock rejectBlock: anotherBlock;
+		yourself
+! !
+
+Trait named: #TPromiseModel
+	package: 'Kernel-Promises'!
+
+!TPromiseModel methodsFor: 'settling'!
+
+signal
+	^ self signal: Error new
+!
+
+signal: anErrorObject
+	self subclassResponsibility
+!
+
+value
+	^ self value: nil
+!
+
+value: anObject
+	self subclassResponsibility
+! !
+
 Trait named: #TThenable
 Trait named: #TThenable
 	package: 'Kernel-Promises'!
 	package: 'Kernel-Promises'!
 
 
@@ -129,5 +197,7 @@ isThenable
 ! !
 ! !
 
 
 Promise setTraitComposition: {TThenable} asTraitComposition!
 Promise setTraitComposition: {TThenable} asTraitComposition!
+Promise class setTraitComposition: {TPromiseModel} asTraitComposition!
+PromiseExecution setTraitComposition: {TPromiseModel} asTraitComposition!
 ! !
 ! !
 
 

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

@@ -15671,6 +15671,789 @@ $globals.PointTest);
 
 
 
 
 
 
+$core.addClass("PromiseTest", $globals.TestCase, "Kernel-Tests");
+$core.addMethod(
+$core.method({
+selector: "testPromiseExecutorAsyncNegativeDo",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseExecutorAsyncNegativeDo\x0a\x09self timeout: 40.\x0a\x09^ (Promise new: [ :m | [ m do: [ self error: 'Intentional' ] ] fork ])\x0a\x09\x09catch: [ :error | self assert: error messageText equals: 'Intentional' ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "catch:", "new:", "fork", "do:", "error:", "assert:equals:", "messageText"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((40));
+return $recv($recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv(m)._do_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx4) {
+//>>excludeEnd("ctx");
+return $self._error_("Intentional");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx4) {$ctx4.fillBlock({},$ctx3,3)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
+//>>excludeEnd("ctx");
+}))._fork();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+})))._catch_((function(error){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_($recv(error)._messageText(),"Intentional");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,4)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseExecutorAsyncNegativeDo",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseExecutorAsyncPositiveDo",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseExecutorAsyncPositiveDo\x0a\x09self timeout: 40.\x0a\x09^ (Promise new: [ :m | [ m do: [ 3 ] ] fork ])\x0a\x09\x09then: [ :result | self assert: result equals: 3 ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "then:", "new:", "fork", "do:", "assert:equals:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((40));
+return $recv($recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv(m)._do_((function(){
+return (3);
+
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
+//>>excludeEnd("ctx");
+}))._fork();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+})))._then_((function(result){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_(result,(3));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({result:result},$ctx1,4)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseExecutorAsyncPositiveDo",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseExecutorAsyncPositiveTry",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseExecutorAsyncPositiveTry\x0a\x09self timeout: 200.\x0a\x09^ (Promise any: {\x0a\x09\x09(Promise new: [ :m | [ m try: [ 3 ] ] fork ])\x0a\x09\x09\x09then: [ :result | self assert: result equals: 3 ].\x0a\x09\x09Promise new: [ :m | [ m value: #timeout ] valueWithTimeout: 20 ]\x0a\x09}) then: [ :result | self assert: result equals: #timeout ].",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "then:", "any:", "new:", "fork", "try:", "assert:equals:", "valueWithTimeout:", "value:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((200));
+return [$recv($recv($globals.Promise)._any_([$recv([$recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv(m)._try_((function(){
+return (3);
+
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
+//>>excludeEnd("ctx");
+}))._fork();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+}))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["new:"]=1
+//>>excludeEnd("ctx");
+][0])._then_((function(result){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return [$self._assert_equals_(result,(3))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["assert:equals:"]=1
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({result:result},$ctx1,4)});
+//>>excludeEnd("ctx");
+})),$recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv(m)._value_("timeout");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,6)});
+//>>excludeEnd("ctx");
+}))._valueWithTimeout_((20));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,5)});
+//>>excludeEnd("ctx");
+}))]))._then_((function(result){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_(result,"timeout");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({result:result},$ctx1,7)});
+//>>excludeEnd("ctx");
+}))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["then:"]=1
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseExecutorAsyncPositiveTry",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseExecutorNegativeDo",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseExecutorNegativeDo\x0a\x09self timeout: 40.\x0a\x09^ (Promise new: [ :m | [ m do: [ self error: 'Intentional' ] ] fork ])\x0a\x09\x09catch: [ :error | self assert: error messageText equals: 'Intentional' ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "catch:", "new:", "fork", "do:", "error:", "assert:equals:", "messageText"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((40));
+return $recv($recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv(m)._do_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx4) {
+//>>excludeEnd("ctx");
+return $self._error_("Intentional");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx4) {$ctx4.fillBlock({},$ctx3,3)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
+//>>excludeEnd("ctx");
+}))._fork();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+})))._catch_((function(error){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_($recv(error)._messageText(),"Intentional");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,4)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseExecutorNegativeDo",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseExecutorNegativeTry",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseExecutorNegativeTry\x0a\x09self timeout: 20.\x0a\x09^ (Promise new: [ :m | m try: [ self error: 'Intentional' ] ])\x0a\x09\x09catch: [ :error | self assert: error messageText equals: 'Intentional' ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "catch:", "new:", "try:", "error:", "assert:equals:", "messageText"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((20));
+return $recv($recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(m)._try_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $self._error_("Intentional");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+})))._catch_((function(error){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_($recv(error)._messageText(),"Intentional");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,3)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseExecutorNegativeTry",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseExecutorPositiveDo",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseExecutorPositiveDo\x0a\x09self timeout: 20.\x0a\x09^ (Promise new: [ :m | m do: [ 3 ] ])\x0a\x09\x09then: [ :result | self assert: result equals: 3 ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "then:", "new:", "do:", "assert:equals:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((20));
+return $recv($recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(m)._do_((function(){
+return (3);
+
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+})))._then_((function(result){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_(result,(3));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({result:result},$ctx1,3)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseExecutorPositiveDo",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseExecutorPositiveTry",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseExecutorPositiveTry\x0a\x09self timeout: 200.\x0a\x09^ (Promise any: {\x0a\x09\x09(Promise new: [ :m | m try: [ 3 ] ])\x0a\x09\x09\x09then: [ :result | self assert: result equals: 3 ].\x0a\x09\x09Promise new: [ :m | [ m value: #timeout ] valueWithTimeout: 20 ]\x0a\x09}) then: [ :result | self assert: result equals: #timeout ].",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "then:", "any:", "new:", "try:", "assert:equals:", "valueWithTimeout:", "value:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((200));
+return [$recv($recv($globals.Promise)._any_([$recv([$recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(m)._try_((function(){
+return (3);
+
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+}))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["new:"]=1
+//>>excludeEnd("ctx");
+][0])._then_((function(result){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return [$self._assert_equals_(result,(3))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["assert:equals:"]=1
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({result:result},$ctx1,3)});
+//>>excludeEnd("ctx");
+})),$recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv(m)._value_("timeout");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,5)});
+//>>excludeEnd("ctx");
+}))._valueWithTimeout_((20));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,4)});
+//>>excludeEnd("ctx");
+}))]))._then_((function(result){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_(result,"timeout");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({result:result},$ctx1,6)});
+//>>excludeEnd("ctx");
+}))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["then:"]=1
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseExecutorPositiveTry",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseNew",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseNew\x0a\x09self timeout: 20.\x0a\x09^ Promise new\x0a\x09\x09then: [ :result | self assert: result equals: nil ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "then:", "new", "assert:equals:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((20));
+return $recv($recv($globals.Promise)._new())._then_((function(result){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_(result,nil);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({result:result},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseNew",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseWithAsyncPassingRejectingExecutor",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseWithAsyncPassingRejectingExecutor\x0a\x09self timeout: 60.\x0a\x09^ (Promise new: [ :m | [\x0a\x09\x09| passPromise |\x0a\x09\x09passPromise := Promise new: [ :m2 | [ m2 signal: 4 ] fork ].\x0a\x09\x09m value: passPromise\x0a\x09] fork ]) catch: [ :err | self assert: err equals: 4 ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "catch:", "new:", "fork", "signal:", "value:", "assert:equals:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((60));
+return $recv([$recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return [$recv((function(){
+var passPromise;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+passPromise=$recv($globals.Promise)._new_((function(m2){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx4) {
+//>>excludeEnd("ctx");
+return $recv((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx5) {
+//>>excludeEnd("ctx");
+return $recv(m2)._signal_((4));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx5) {$ctx5.fillBlock({},$ctx4,4)});
+//>>excludeEnd("ctx");
+}))._fork();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx4) {$ctx4.fillBlock({m2:m2},$ctx3,3)});
+//>>excludeEnd("ctx");
+}));
+return $recv(m)._value_(passPromise);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({passPromise:passPromise},$ctx2,2)});
+//>>excludeEnd("ctx");
+}))._fork()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["fork"]=1
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+}))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["new:"]=1
+//>>excludeEnd("ctx");
+][0])._catch_((function(err){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_(err,(4));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({err:err},$ctx1,5)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseWithAsyncPassingRejectingExecutor",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseWithAsyncPassingResolvingExecutor",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseWithAsyncPassingResolvingExecutor\x0a\x09self timeout: 60.\x0a\x09^ (Promise new: [ :m | [\x0a\x09\x09| passPromise |\x0a\x09\x09passPromise := Promise new: [ :m2 | [ m2 value: 3 ] fork ].\x0a\x09\x09m value: passPromise\x0a\x09] fork ]) then: [ :result | self assert: result equals: 3 ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "then:", "new:", "fork", "value:", "assert:equals:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((60));
+return $recv([$recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return [$recv((function(){
+var passPromise;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+passPromise=$recv($globals.Promise)._new_((function(m2){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx4) {
+//>>excludeEnd("ctx");
+return $recv((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx5) {
+//>>excludeEnd("ctx");
+return [$recv(m2)._value_((3))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx5.sendIdx["value:"]=1
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx5) {$ctx5.fillBlock({},$ctx4,4)});
+//>>excludeEnd("ctx");
+}))._fork();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx4) {$ctx4.fillBlock({m2:m2},$ctx3,3)});
+//>>excludeEnd("ctx");
+}));
+return $recv(m)._value_(passPromise);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({passPromise:passPromise},$ctx2,2)});
+//>>excludeEnd("ctx");
+}))._fork()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["fork"]=1
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+}))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["new:"]=1
+//>>excludeEnd("ctx");
+][0])._then_((function(result){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_(result,(3));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({result:result},$ctx1,5)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseWithAsyncPassingResolvingExecutor",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseWithAsyncRejectingExecutor",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseWithAsyncRejectingExecutor\x0a\x09self timeout: 40.\x0a\x09^ (Promise new: [ :m | [ m signal: 4 ] fork ])\x0a\x09\x09catch: [ :err | self assert: err equals: 4 ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "catch:", "new:", "fork", "signal:", "assert:equals:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((40));
+return $recv($recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv(m)._signal_((4));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
+//>>excludeEnd("ctx");
+}))._fork();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+})))._catch_((function(err){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_(err,(4));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({err:err},$ctx1,3)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseWithAsyncRejectingExecutor",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseWithAsyncResolvingExecutor",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseWithAsyncResolvingExecutor\x0a\x09self timeout: 40.\x0a\x09^ (Promise new: [ :m | [ m value: 3 ] fork ])\x0a\x09\x09then: [ :result | self assert: result equals: 3 ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "then:", "new:", "fork", "value:", "assert:equals:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((40));
+return $recv($recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv(m)._value_((3));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
+//>>excludeEnd("ctx");
+}))._fork();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+})))._then_((function(result){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_(result,(3));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({result:result},$ctx1,3)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseWithAsyncResolvingExecutor",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseWithRejectingExecutor",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseWithRejectingExecutor\x0a\x09self timeout: 20.\x0a\x09^ (Promise new: [ :m | m signal: 4 ])\x0a\x09\x09catch: [ :err | self assert: err equals: 4 ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "catch:", "new:", "signal:", "assert:equals:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((20));
+return $recv($recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(m)._signal_((4));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+})))._catch_((function(err){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_(err,(4));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({err:err},$ctx1,2)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseWithRejectingExecutor",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+$core.addMethod(
+$core.method({
+selector: "testPromiseWithResolvingExecutor",
+protocol: " tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testPromiseWithResolvingExecutor\x0a\x09self timeout: 20.\x0a\x09^ (Promise new: [ :m | m value: 3 ])\x0a\x09\x09then: [ :result | self assert: result equals: 3 ]",
+referencedClasses: ["Promise"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["timeout:", "then:", "new:", "value:", "assert:equals:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._timeout_((20));
+return $recv($recv($globals.Promise)._new_((function(m){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(m)._value_((3));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({m:m},$ctx1,1)});
+//>>excludeEnd("ctx");
+})))._then_((function(result){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._assert_equals_(result,(3));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({result:result},$ctx1,2)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testPromiseWithResolvingExecutor",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PromiseTest);
+
+
+
 $core.addClass("QueueTest", $globals.TestCase, "Kernel-Tests");
 $core.addClass("QueueTest", $globals.TestCase, "Kernel-Tests");
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({

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

@@ -2780,6 +2780,108 @@ testTranslateBy
 	self assert: (3@3 translateBy: 3 negated @0) equals: 0@3.
 	self assert: (3@3 translateBy: 3 negated @0) equals: 0@3.
 ! !
 ! !
 
 
+TestCase subclass: #PromiseTest
+	slots: {}
+	package: 'Kernel-Tests'!
+
+!PromiseTest methodsFor: ' tests'!
+
+testPromiseExecutorAsyncNegativeDo
+	self timeout: 40.
+	^ (Promise new: [ :m | [ m do: [ self error: 'Intentional' ] ] fork ])
+		catch: [ :error | self assert: error messageText equals: 'Intentional' ]
+!
+
+testPromiseExecutorAsyncPositiveDo
+	self timeout: 40.
+	^ (Promise new: [ :m | [ m do: [ 3 ] ] fork ])
+		then: [ :result | self assert: result equals: 3 ]
+!
+
+testPromiseExecutorAsyncPositiveTry
+	self timeout: 200.
+	^ (Promise any: {
+		(Promise new: [ :m | [ m try: [ 3 ] ] fork ])
+			then: [ :result | self assert: result equals: 3 ].
+		Promise new: [ :m | [ m value: #timeout ] valueWithTimeout: 20 ]
+	}) then: [ :result | self assert: result equals: #timeout ].
+!
+
+testPromiseExecutorNegativeDo
+	self timeout: 40.
+	^ (Promise new: [ :m | [ m do: [ self error: 'Intentional' ] ] fork ])
+		catch: [ :error | self assert: error messageText equals: 'Intentional' ]
+!
+
+testPromiseExecutorNegativeTry
+	self timeout: 20.
+	^ (Promise new: [ :m | m try: [ self error: 'Intentional' ] ])
+		catch: [ :error | self assert: error messageText equals: 'Intentional' ]
+!
+
+testPromiseExecutorPositiveDo
+	self timeout: 20.
+	^ (Promise new: [ :m | m do: [ 3 ] ])
+		then: [ :result | self assert: result equals: 3 ]
+!
+
+testPromiseExecutorPositiveTry
+	self timeout: 200.
+	^ (Promise any: {
+		(Promise new: [ :m | m try: [ 3 ] ])
+			then: [ :result | self assert: result equals: 3 ].
+		Promise new: [ :m | [ m value: #timeout ] valueWithTimeout: 20 ]
+	}) then: [ :result | self assert: result equals: #timeout ].
+!
+
+testPromiseNew
+	self timeout: 20.
+	^ Promise new
+		then: [ :result | self assert: result equals: nil ]
+!
+
+testPromiseWithAsyncPassingRejectingExecutor
+	self timeout: 60.
+	^ (Promise new: [ :m | [
+		| passPromise |
+		passPromise := Promise new: [ :m2 | [ m2 signal: 4 ] fork ].
+		m value: passPromise
+	] fork ]) catch: [ :err | self assert: err equals: 4 ]
+!
+
+testPromiseWithAsyncPassingResolvingExecutor
+	self timeout: 60.
+	^ (Promise new: [ :m | [
+		| passPromise |
+		passPromise := Promise new: [ :m2 | [ m2 value: 3 ] fork ].
+		m value: passPromise
+	] fork ]) then: [ :result | self assert: result equals: 3 ]
+!
+
+testPromiseWithAsyncRejectingExecutor
+	self timeout: 40.
+	^ (Promise new: [ :m | [ m signal: 4 ] fork ])
+		catch: [ :err | self assert: err equals: 4 ]
+!
+
+testPromiseWithAsyncResolvingExecutor
+	self timeout: 40.
+	^ (Promise new: [ :m | [ m value: 3 ] fork ])
+		then: [ :result | self assert: result equals: 3 ]
+!
+
+testPromiseWithRejectingExecutor
+	self timeout: 20.
+	^ (Promise new: [ :m | m signal: 4 ])
+		catch: [ :err | self assert: err equals: 4 ]
+!
+
+testPromiseWithResolvingExecutor
+	self timeout: 20.
+	^ (Promise new: [ :m | m value: 3 ])
+		then: [ :result | self assert: result equals: 3 ]
+! !
+
 TestCase subclass: #QueueTest
 TestCase subclass: #QueueTest
 	slots: {}
 	slots: {}
 	package: 'Kernel-Tests'!
 	package: 'Kernel-Tests'!

+ 3 - 37
lang/src/Platform-ImportExport.js

@@ -3130,30 +3130,27 @@ selector: "commit:",
 protocol: "committing",
 protocol: "committing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aPackage"],
 args: ["aPackage"],
-source: "commit: aPackage\x0a\x09self \x0a\x09\x09commit: aPackage\x0a\x09\x09onSuccess: []\x0a\x09\x09onError: [ :error |\x0a\x09\x09\x09PackageCommitError new\x0a\x09\x09\x09\x09messageText: 'Commiting failed with reason: \x22' , (error responseText) , '\x22';\x0a\x09\x09\x09\x09signal ]",
+source: "commit: aPackage\x0a\x09self \x0a\x09\x09commit: aPackage\x0a\x09\x09onSuccess: []\x0a\x09\x09onError: [ :error |\x0a\x09\x09\x09PackageCommitError\x0a\x09\x09\x09\x09signal: 'Commiting failed with reason: \x22' , error responseText , '\x22' ]",
 referencedClasses: ["PackageCommitError"],
 referencedClasses: ["PackageCommitError"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["commit:onSuccess:onError:", "messageText:", "new", ",", "responseText", "signal"]
+messageSends: ["commit:onSuccess:onError:", "signal:", ",", "responseText"]
 }, function ($methodClass){ return function (aPackage){
 }, function ($methodClass){ return function (aPackage){
 var self=this,$self=this;
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
 $self._commit_onSuccess_onError_(aPackage,(function(){
 $self._commit_onSuccess_onError_(aPackage,(function(){
 
 
 }),(function(error){
 }),(function(error){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-$1=$recv($globals.PackageCommitError)._new();
-$recv($1)._messageText_([$recv("Commiting failed with reason: \x22".__comma($recv(error)._responseText())).__comma("\x22")
+return $recv($globals.PackageCommitError)._signal_([$recv("Commiting failed with reason: \x22".__comma($recv(error)._responseText())).__comma("\x22")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 ,$ctx2.sendIdx[","]=1
 ,$ctx2.sendIdx[","]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 ][0]);
 ][0]);
-return $recv($1)._signal();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,2)});
 }, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,2)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
@@ -3420,37 +3417,6 @@ return self;
 }; }),
 }; }),
 $globals.PackageHandler);
 $globals.PackageHandler);
 
 
-$core.addMethod(
-$core.method({
-selector: "onCommitError:",
-protocol: "error handling",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anError"],
-source: "onCommitError: anError\x0a\x09PackageCommitError new\x0a\x09\x09messageText: 'Commiting failed with reason: \x22' , (anError responseText) , '\x22';\x0a\x09\x09signal",
-referencedClasses: ["PackageCommitError"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["messageText:", "new", ",", "responseText", "signal"]
-}, function ($methodClass){ return function (anError){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1;
-$1=$recv($globals.PackageCommitError)._new();
-$recv($1)._messageText_([$recv("Commiting failed with reason: \x22".__comma($recv(anError)._responseText())).__comma("\x22")
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx[","]=1
-//>>excludeEnd("ctx");
-][0]);
-$recv($1)._signal();
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"onCommitError:",{anError:anError})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.PackageHandler);
-
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "setPath:forPackage:",
 selector: "setPath:forPackage:",

+ 2 - 11
lang/src/Platform-ImportExport.st

@@ -794,9 +794,8 @@ commit: aPackage
 		commit: aPackage
 		commit: aPackage
 		onSuccess: []
 		onSuccess: []
 		onError: [ :error |
 		onError: [ :error |
-			PackageCommitError new
-				messageText: 'Commiting failed with reason: "' , (error responseText) , '"';
-				signal ]
+			PackageCommitError
+				signal: 'Commiting failed with reason: "' , error responseText , '"' ]
 !
 !
 
 
 commit: aPackage onSuccess: aBlock onError: anotherBlock
 commit: aPackage onSuccess: aBlock onError: anotherBlock
@@ -826,14 +825,6 @@ commitStFileFor: aPackage onSuccess: aBlock onError: anotherBlock
 		onError: anotherBlock
 		onError: anotherBlock
 ! !
 ! !
 
 
-!PackageHandler methodsFor: 'error handling'!
-
-onCommitError: anError
-	PackageCommitError new
-		messageText: 'Commiting failed with reason: "' , (anError responseText) , '"';
-		signal
-! !
-
 !PackageHandler methodsFor: 'factory'!
 !PackageHandler methodsFor: 'factory'!
 
 
 chunkExporter
 chunkExporter

+ 7 - 10
lang/src/SUnit.js

@@ -736,20 +736,17 @@ selector: "signalFailure:",
 protocol: "private",
 protocol: "private",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString"],
 args: ["aString"],
-source: "signalFailure: aString\x0a\x09TestFailure new\x0a\x09\x09messageText: aString;\x0a\x09\x09signal",
+source: "signalFailure: aString\x0a\x09TestFailure signal: aString",
 referencedClasses: ["TestFailure"],
 referencedClasses: ["TestFailure"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["messageText:", "new", "signal"]
+messageSends: ["signal:"]
 }, function ($methodClass){ return function (aString){
 }, function ($methodClass){ return function (aString){
 var self=this,$self=this;
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($globals.TestFailure)._new();
-$recv($1)._messageText_(aString);
-$recv($1)._signal();
+$recv($globals.TestFailure)._signal_(aString);
 return self;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"signalFailure:",{aString:aString})});
 }, function($ctx1) {$ctx1.fill(self,"signalFailure:",{aString:aString})});
@@ -1053,11 +1050,11 @@ selector: "execute:",
 protocol: "running",
 protocol: "running",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aBlock"],
 args: ["aBlock"],
-source: "execute: aBlock\x0a\x09| failed result |\x0a\x09\x0a\x09testCase context: self.\x0a\x09[\x0a\x09\x09failed := true.\x0a\x09\x09result := aBlock value.\x0a\x09\x09testCase isAsync ifFalse: [\x0a\x09\x09\x09testCase assert: result isThenable not description: testCase asString, ' returned promise without sending #timeout:' ].\x0a\x09\x09failed := false\x0a\x09]\x0a\x09\x09ensure: [\x0a\x09\x09\x09\x22testCase context: nil.\x22\x0a\x09\x09\x09\x0a\x09\x09\x09(failed and: [ testCase isAsync ]) ifTrue: [ testCase finished ].\x0a\x09\x09\x09testCase isAsync\x0a\x09\x09\x09\x09ifFalse: [ testCase tearDown ]\x0a\x09\x09\x09\x09ifTrue: [ result isThenable ifTrue: [\x0a\x09\x09\x09\x09\x09result\x0a\x09\x09\x09\x09\x09\x09then: [ testCase isAsync ifTrue: [ self execute: [ testCase finished ] ] ]\x0a\x09\x09\x09\x09\x09\x09catch: [ :error | testCase isAsync ifTrue: [ self execute: [ error signal ] ] ] ] ] ]",
-referencedClasses: [],
+source: "execute: aBlock\x0a\x09| failed result |\x0a\x09\x0a\x09testCase context: self.\x0a\x09[\x0a\x09\x09failed := true.\x0a\x09\x09result := aBlock value.\x0a\x09\x09testCase isAsync ifFalse: [\x0a\x09\x09\x09testCase assert: result isThenable not description: testCase asString, ' returned promise without sending #timeout:' ].\x0a\x09\x09failed := false\x0a\x09]\x0a\x09\x09ensure: [\x0a\x09\x09\x09\x22testCase context: nil.\x22\x0a\x09\x09\x09\x0a\x09\x09\x09(failed and: [ testCase isAsync ]) ifTrue: [ testCase finished ].\x0a\x09\x09\x09testCase isAsync\x0a\x09\x09\x09\x09ifFalse: [ testCase tearDown ]\x0a\x09\x09\x09\x09ifTrue: [ result isThenable ifTrue: [\x0a\x09\x09\x09\x09\x09result\x0a\x09\x09\x09\x09\x09\x09then: [ testCase isAsync ifTrue: [ self execute: [ testCase finished ] ] ]\x0a\x09\x09\x09\x09\x09\x09catch: [ :error | testCase isAsync ifTrue: [ self execute: [ (Smalltalk asSmalltalkException: error) pass ] ] ] ] ] ]",
+referencedClasses: ["Smalltalk"],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["context:", "ensure:", "value", "ifFalse:", "isAsync", "assert:description:", "not", "isThenable", ",", "asString", "ifTrue:", "and:", "finished", "ifFalse:ifTrue:", "tearDown", "then:catch:", "execute:", "signal"]
+messageSends: ["context:", "ensure:", "value", "ifFalse:", "isAsync", "assert:description:", "not", "isThenable", ",", "asString", "ifTrue:", "and:", "finished", "ifFalse:ifTrue:", "tearDown", "then:catch:", "execute:", "pass", "asSmalltalkException:"]
 }, function ($methodClass){ return function (aBlock){
 }, function ($methodClass){ return function (aBlock){
 var self=this,$self=this;
 var self=this,$self=this;
 var failed,result;
 var failed,result;
@@ -1149,7 +1146,7 @@ return $self._execute_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx4) {
 return $core.withContext(function($ctx4) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
-return $recv(error)._signal();
+return $recv($recv($globals.Smalltalk)._asSmalltalkException_(error))._pass();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx4) {$ctx4.fillBlock({},$ctx3,14)});
 }, function($ctx4) {$ctx4.fillBlock({},$ctx3,14)});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");

+ 2 - 4
lang/src/SUnit.st

@@ -146,9 +146,7 @@ errorIfNotAsync: aString
 !TestCase methodsFor: 'private'!
 !TestCase methodsFor: 'private'!
 
 
 signalFailure: aString
 signalFailure: aString
-	TestFailure new
-		messageText: aString;
-		signal
+	TestFailure signal: aString
 ! !
 ! !
 
 
 !TestCase methodsFor: 'running'!
 !TestCase methodsFor: 'running'!
@@ -299,7 +297,7 @@ execute: aBlock
 				ifTrue: [ result isThenable ifTrue: [
 				ifTrue: [ result isThenable ifTrue: [
 					result
 					result
 						then: [ testCase isAsync ifTrue: [ self execute: [ testCase finished ] ] ]
 						then: [ testCase isAsync ifTrue: [ self execute: [ testCase finished ] ] ]
-						catch: [ :error | testCase isAsync ifTrue: [ self execute: [ error signal ] ] ] ] ] ]
+						catch: [ :error | testCase isAsync ifTrue: [ self execute: [ (Smalltalk asSmalltalkException: error) pass ] ] ] ] ] ]
 !
 !
 
 
 start
 start