Browse Source

IRReturn-related testing protocol overhaul.

Herbert Vojčík 7 years ago
parent
commit
8170a58ff5
5 changed files with 117 additions and 281 deletions
  1. 1 0
      API-CHANGES.txt
  2. 33 182
      src/Compiler-IR.js
  3. 5 41
      src/Compiler-IR.st
  4. 57 47
      src/Compiler-Inlining.js
  5. 21 11
      src/Compiler-Inlining.st

+ 1 - 0
API-CHANGES.txt

@@ -1,6 +1,7 @@
 0.18.0:
 
 * Remove class RethrowErrorHandler (hack for cli before 0.12.3).
+* Some internal API changes in Compiler-*.
 
 - Object >>
   - throw:

+ 33 - 182
src/Compiler-IR.js

@@ -1144,24 +1144,6 @@ messageSends: ["parent:", "add:", "instructions"]
 }),
 $globals.IRInstruction);
 
-$core.addMethod(
-$core.method({
-selector: "canBeAssigned",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return true;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "canBeAssigned\x0a\x09^ true",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRInstruction);
-
 $core.addMethod(
 $core.method({
 selector: "instructions",
@@ -1228,24 +1210,6 @@ messageSends: []
 }),
 $globals.IRInstruction);
 
-$core.addMethod(
-$core.method({
-selector: "isLocalReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return false;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isLocalReturn\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRInstruction);
-
 $core.addMethod(
 $core.method({
 selector: "isMethod",
@@ -1264,24 +1228,6 @@ messageSends: []
 }),
 $globals.IRInstruction);
 
-$core.addMethod(
-$core.method({
-selector: "isReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return false;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isReturn\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRInstruction);
-
 $core.addMethod(
 $core.method({
 selector: "isSend",
@@ -1541,6 +1487,24 @@ messageSends: ["ifNotNil:", "parent", "scope"]
 }),
 $globals.IRInstruction);
 
+$core.addMethod(
+$core.method({
+selector: "yieldsValue",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return true;
+
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "yieldsValue\x0a\x09^ true",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.IRInstruction);
+
 
 $core.addMethod(
 $core.method({
@@ -2326,24 +2290,6 @@ messageSends: ["visitIRReturn:"]
 }),
 $globals.IRReturn);
 
-$core.addMethod(
-$core.method({
-selector: "canBeAssigned",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return false;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "canBeAssigned\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRReturn);
-
 $core.addMethod(
 $core.method({
 selector: "expression",
@@ -2369,110 +2315,51 @@ $globals.IRReturn);
 
 $core.addMethod(
 $core.method({
-selector: "isBlockReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return false;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isBlockReturn\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRReturn);
-
-$core.addMethod(
-$core.method({
-selector: "isLocalReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return true;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isLocalReturn\x0a\x09^ true",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRReturn);
-
-$core.addMethod(
-$core.method({
-selector: "isNonLocalReturn",
-protocol: 'testing',
+selector: "scope",
+protocol: 'accessing',
 fn: function (){
 var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return $recv(self._isLocalReturn())._not();
+var $1,$receiver;
+$1=self["@scope"];
+if(($receiver = $1) == null || $receiver.isNil){
+return $recv(self._parent())._scope();
+} else {
+return $1;
+};
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"isNonLocalReturn",{},$globals.IRReturn)});
+}, function($ctx1) {$ctx1.fill(self,"scope",{},$globals.IRReturn)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "isNonLocalReturn\x0a\x09^ self isLocalReturn not",
+source: "scope\x0a\x09^ scope ifNil: [ self parent scope ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["not", "isLocalReturn"]
+messageSends: ["ifNil:", "scope", "parent"]
 }),
 $globals.IRReturn);
 
 $core.addMethod(
 $core.method({
-selector: "isReturn",
+selector: "yieldsValue",
 protocol: 'testing',
 fn: function (){
 var self=this;
-return true;
+return false;
 
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "isReturn\x0a\x09^ true",
+source: "yieldsValue\x0a\x09^ false",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
 }),
 $globals.IRReturn);
 
-$core.addMethod(
-$core.method({
-selector: "scope",
-protocol: 'accessing',
-fn: function (){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1,$receiver;
-$1=self["@scope"];
-if(($receiver = $1) == null || $receiver.isNil){
-return $recv(self._parent())._scope();
-} else {
-return $1;
-};
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"scope",{},$globals.IRReturn)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "scope\x0a\x09^ scope ifNil: [ self parent scope ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["ifNil:", "scope", "parent"]
-}),
-$globals.IRReturn);
-
 
 
 $core.addClass('IRBlockReturn', $globals.IRReturn, [], 'Compiler-IR');
@@ -2502,24 +2389,6 @@ messageSends: ["visitIRBlockReturn:"]
 }),
 $globals.IRBlockReturn);
 
-$core.addMethod(
-$core.method({
-selector: "isBlockReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return true;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isBlockReturn\x0a\x09^ true",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRBlockReturn);
-
 
 
 $core.addClass('IRNonLocalReturn', $globals.IRReturn, [], 'Compiler-IR');
@@ -2549,24 +2418,6 @@ messageSends: ["visitIRNonLocalReturn:"]
 }),
 $globals.IRNonLocalReturn);
 
-$core.addMethod(
-$core.method({
-selector: "isLocalReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return false;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isLocalReturn\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRNonLocalReturn);
-
 
 
 $core.addClass('IRTempDeclaration', $globals.IRScopedInstruction, ['name'], 'Compiler-IR');

+ 5 - 41
src/Compiler-IR.st

@@ -309,10 +309,6 @@ replaceWith: anIRInstruction
 
 !IRInstruction methodsFor: 'testing'!
 
-canBeAssigned
-	^ true
-!
-
 isClosure
 	^ false
 !
@@ -321,18 +317,10 @@ isInlined
 	^ false
 !
 
-isLocalReturn
-	^ false
-!
-
 isMethod
 	^ false
 !
 
-isReturn
-	^ false
-!
-
 isSend
 	^ false
 !
@@ -351,6 +339,10 @@ isVariable
 
 needsBoxingAsReceiver
 	^ true
+!
+
+yieldsValue
+	^ true
 ! !
 
 !IRInstruction methodsFor: 'visiting'!
@@ -571,24 +563,8 @@ scope
 
 !IRReturn methodsFor: 'testing'!
 
-canBeAssigned
+yieldsValue
 	^ false
-!
-
-isBlockReturn
-	^ false
-!
-
-isLocalReturn
-	^ true
-!
-
-isNonLocalReturn
-	^ self isLocalReturn not
-!
-
-isReturn
-	^ true
 ! !
 
 !IRReturn methodsFor: 'visiting'!
@@ -603,12 +579,6 @@ IRReturn subclass: #IRBlockReturn
 !IRBlockReturn commentStamp!
 Smalltalk blocks return their last statement. I am a implicit block return instruction.!
 
-!IRBlockReturn methodsFor: 'testing'!
-
-isBlockReturn
-	^ true
-! !
-
 !IRBlockReturn methodsFor: 'visiting'!
 
 accept: aVisitor
@@ -624,12 +594,6 @@ Non local returns are handled using a try/catch JavaScript statement.
 
 See `IRNonLocalReturnHandling` class.!
 
-!IRNonLocalReturn methodsFor: 'testing'!
-
-isLocalReturn
-	^ false
-! !
-
 !IRNonLocalReturn methodsFor: 'visiting'!
 
 accept: aVisitor

+ 57 - 47
src/Compiler-Inlining.js

@@ -1511,7 +1511,7 @@ var inlinedClosure,sequence,statements;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$3,$5,$6,$4,$7,$9,$11,$13,$14,$15,$12,$10,$17,$19,$20,$18,$16,$8,$23,$22,$24,$21,$25,$27,$26;
+var $1,$2,$3,$5,$6,$4,$7,$9,$11,$13,$14,$15,$12,$10,$17,$19,$20,$18,$16,$8;
 inlinedClosure=self._inlinedClosure();
 $1=inlinedClosure;
 $2=$recv(anIRClosure)._scope();
@@ -1649,38 +1649,7 @@ $ctx3.sendIdx["add:"]=7;
 }, function($ctx3) {$ctx3.fillBlock({each:each},$ctx2,4)});
 //>>excludeEnd("ctx");
 }));
-$23=$recv(statements)._last();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["last"]=1;
-//>>excludeEnd("ctx");
-$22=$recv($23)._isReturn();
-$21=$recv($22)._and_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx3) {
-//>>excludeEnd("ctx");
-$24=$recv(statements)._last();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx3.sendIdx["last"]=2;
-//>>excludeEnd("ctx");
-return $recv($24)._isBlockReturn();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,5)});
-//>>excludeEnd("ctx");
-}));
-if($core.assert($21)){
-$25=sequence;
-$27=$recv(statements)._last();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["last"]=3;
-//>>excludeEnd("ctx");
-$26=$recv($27)._expression();
-return $recv($25)._add_($26);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["add:"]=8;
-//>>excludeEnd("ctx");
-} else {
-return $recv(sequence)._add_($recv(statements)._last());
-};
+return $recv(sequence)._add_($recv($recv(statements)._last())._asInlinedBlockResult());
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)});
 //>>excludeEnd("ctx");
@@ -1692,10 +1661,10 @@ return inlinedClosure;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anIRClosure"],
-source: "inlineClosure: anIRClosure\x0a\x09| inlinedClosure sequence statements |\x0a\x0a\x09inlinedClosure := self inlinedClosure.\x0a\x09inlinedClosure \x0a\x09\x09scope: anIRClosure scope;\x0a\x09\x09parent: anIRClosure parent.\x0a\x0a\x09\x22Add the possible temp declarations\x22\x0a\x09anIRClosure tempDeclarations do: [ :each |\x0a\x09\x09\x09inlinedClosure add: each ].\x0a\x0a\x09\x22Add a block sequence\x22\x0a\x09sequence := self inlinedSequence.\x0a\x0a\x09\x22Map the closure arguments to the receiver of the message send\x22\x0a\x09anIRClosure arguments do: [ :each |\x0a\x09\x09inlinedClosure add: (IRTempDeclaration new name: each; yourself).\x0a\x09\x09sequence add: (IRAssignment new\x0a\x09\x09\x09add: (IRVariable new variable: (AliasVar new scope: inlinedClosure scope; name: each; yourself));\x0a\x09\x09\x09add: (IRVariable new variable: (AliasVar new scope: inlinedClosure scope; name: '$receiver'; yourself));\x0a\x09\x09\x09yourself) ].\x0a\x09\x09\x09\x0a\x09\x22To ensure the correct order of the closure instructions: first the temps then the sequence\x22\x0a\x09inlinedClosure add: sequence.\x0a\x0a\x09\x22Get all the statements\x22\x0a\x09statements := anIRClosure sequence instructions.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements allButLast do: [ :each | sequence add: each ].\x0a\x0a\x09\x09\x22Inlined closures don't have implicit local returns\x22\x0a\x09\x09(statements last isReturn and: [ statements last isBlockReturn ])\x0a\x09\x09\x09ifTrue: [ sequence add: statements last expression ]\x0a\x09\x09\x09ifFalse: [ sequence add: statements last ] ].\x0a\x0a\x09^ inlinedClosure",
+source: "inlineClosure: anIRClosure\x0a\x09| inlinedClosure sequence statements |\x0a\x0a\x09inlinedClosure := self inlinedClosure.\x0a\x09inlinedClosure \x0a\x09\x09scope: anIRClosure scope;\x0a\x09\x09parent: anIRClosure parent.\x0a\x0a\x09\x22Add the possible temp declarations\x22\x0a\x09anIRClosure tempDeclarations do: [ :each |\x0a\x09\x09\x09inlinedClosure add: each ].\x0a\x0a\x09\x22Add a block sequence\x22\x0a\x09sequence := self inlinedSequence.\x0a\x0a\x09\x22Map the closure arguments to the receiver of the message send\x22\x0a\x09anIRClosure arguments do: [ :each |\x0a\x09\x09inlinedClosure add: (IRTempDeclaration new name: each; yourself).\x0a\x09\x09sequence add: (IRAssignment new\x0a\x09\x09\x09add: (IRVariable new variable: (AliasVar new scope: inlinedClosure scope; name: each; yourself));\x0a\x09\x09\x09add: (IRVariable new variable: (AliasVar new scope: inlinedClosure scope; name: '$receiver'; yourself));\x0a\x09\x09\x09yourself) ].\x0a\x09\x09\x09\x0a\x09\x22To ensure the correct order of the closure instructions: first the temps then the sequence\x22\x0a\x09inlinedClosure add: sequence.\x0a\x0a\x09\x22Get all the statements\x22\x0a\x09statements := anIRClosure sequence instructions.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements allButLast do: [ :each | sequence add: each ].\x0a\x0a\x09\x09\x22Inlined closures change local returns into result value itself\x22\x0a\x09\x09sequence add: statements last asInlinedBlockResult ].\x0a\x0a\x09^ inlinedClosure",
 referencedClasses: ["IRTempDeclaration", "IRAssignment", "IRVariable", "AliasVar"],
 //>>excludeEnd("ide");
-messageSends: ["inlinedClosure", "scope:", "scope", "parent:", "parent", "do:", "tempDeclarations", "add:", "inlinedSequence", "arguments", "name:", "new", "yourself", "variable:", "instructions", "sequence", "ifNotEmpty:", "allButLast", "ifTrue:ifFalse:", "and:", "isReturn", "last", "isBlockReturn", "expression"]
+messageSends: ["inlinedClosure", "scope:", "scope", "parent:", "parent", "do:", "tempDeclarations", "add:", "inlinedSequence", "arguments", "name:", "new", "yourself", "variable:", "instructions", "sequence", "ifNotEmpty:", "allButLast", "asInlinedBlockResult", "last"]
 }),
 $globals.IRSendInliner);
 
@@ -2138,12 +2107,12 @@ selector: "inlineClosure:",
 protocol: 'inlining',
 fn: function (anIRClosure){
 var self=this;
-var inlinedClosure,statements;
+var closure,statements;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 var $2,$1,$3,$5,$4;
-inlinedClosure=(
+closure=(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
@@ -2151,7 +2120,7 @@ $ctx1.supercall = true,
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = false;
 //>>excludeEnd("ctx");;
-statements=$recv($recv(inlinedClosure)._sequence())._instructions();
+statements=$recv($recv(closure)._sequence())._instructions();
 $recv(statements)._ifNotEmpty_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -2160,7 +2129,7 @@ $2=$recv(statements)._last();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx2.sendIdx["last"]=1;
 //>>excludeEnd("ctx");
-$1=$recv($2)._canBeAssigned();
+$1=$recv($2)._yieldsValue();
 if($core.assert($1)){
 $3=$recv(statements)._last();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2179,17 +2148,17 @@ return $recv($3)._replaceWith_($4);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
 }));
-return inlinedClosure;
+return closure;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"inlineClosure:",{anIRClosure:anIRClosure,inlinedClosure:inlinedClosure,statements:statements},$globals.IRAssignmentInliner)});
+}, function($ctx1) {$ctx1.fill(self,"inlineClosure:",{anIRClosure:anIRClosure,closure:closure,statements:statements},$globals.IRAssignmentInliner)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anIRClosure"],
-source: "inlineClosure: anIRClosure\x0a\x09| inlinedClosure statements |\x0a\x0a\x09inlinedClosure := super inlineClosure: anIRClosure.\x0a\x09statements := inlinedClosure sequence instructions.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements last canBeAssigned ifTrue: [\x0a\x09\x09\x09statements last replaceWith: (IRAssignment new\x0a\x09\x09\x09\x09add: self assignment left;\x0a\x09\x09\x09\x09add: statements last copy;\x0a\x09\x09\x09\x09yourself) ] ].\x0a\x0a\x09^ inlinedClosure",
+source: "inlineClosure: anIRClosure\x0a\x09| closure statements |\x0a\x0a\x09closure := super inlineClosure: anIRClosure.\x0a\x09statements := closure sequence instructions.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements last yieldsValue ifTrue: [\x0a\x09\x09\x09statements last replaceWith: (IRAssignment new\x0a\x09\x09\x09\x09add: self assignment left;\x0a\x09\x09\x09\x09add: statements last copy;\x0a\x09\x09\x09\x09yourself) ] ].\x0a\x0a\x09^ closure",
 referencedClasses: ["IRAssignment"],
 //>>excludeEnd("ide");
-messageSends: ["inlineClosure:", "instructions", "sequence", "ifNotEmpty:", "ifTrue:", "canBeAssigned", "last", "replaceWith:", "add:", "new", "left", "assignment", "copy", "yourself"]
+messageSends: ["inlineClosure:", "instructions", "sequence", "ifNotEmpty:", "ifTrue:", "yieldsValue", "last", "replaceWith:", "add:", "new", "left", "assignment", "copy", "yourself"]
 }),
 $globals.IRAssignmentInliner);
 
@@ -2227,8 +2196,8 @@ $2=$recv(statements)._last();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx2.sendIdx["last"]=1;
 //>>excludeEnd("ctx");
-$1=$recv($2)._isReturn();
-if(!$core.assert($1)){
+$1=$recv($2)._yieldsValue();
+if($core.assert($1)){
 $3=$recv(statements)._last();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx2.sendIdx["last"]=2;
@@ -2249,10 +2218,10 @@ return closure;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anIRClosure"],
-source: "inlineClosure: anIRClosure\x0a\x09| closure statements |\x0a\x0a\x09closure := super inlineClosure: anIRClosure.\x0a\x09statements := closure sequence instructions.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements last isReturn\x0a\x09\x09\x09ifFalse: [ statements last replaceWith: (IRReturn new\x0a\x09\x09\x09\x09add: statements last copy;\x0a\x09\x09\x09\x09yourself)] ].\x0a\x0a\x09^ closure",
+source: "inlineClosure: anIRClosure\x0a\x09| closure statements |\x0a\x0a\x09closure := super inlineClosure: anIRClosure.\x0a\x09statements := closure sequence instructions.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements last yieldsValue ifTrue: [\x0a\x09\x09\x09statements last replaceWith: (IRReturn new\x0a\x09\x09\x09\x09add: statements last copy;\x0a\x09\x09\x09\x09yourself)] ].\x0a\x0a\x09^ closure",
 referencedClasses: ["IRReturn"],
 //>>excludeEnd("ide");
-messageSends: ["inlineClosure:", "instructions", "sequence", "ifNotEmpty:", "ifFalse:", "isReturn", "last", "replaceWith:", "add:", "new", "copy", "yourself"]
+messageSends: ["inlineClosure:", "instructions", "sequence", "ifNotEmpty:", "ifTrue:", "yieldsValue", "last", "replaceWith:", "add:", "new", "copy", "yourself"]
 }),
 $globals.IRReturnInliner);
 
@@ -2414,4 +2383,45 @@ $core.addClass('InliningError', $globals.SemanticError, [], 'Compiler-Inlining')
 $globals.InliningError.comment="Instances of InliningError are signaled when using an `InliningCodeGenerator`in a `Compiler`.";
 //>>excludeEnd("ide");
 
+$core.addMethod(
+$core.method({
+selector: "asInlinedBlockResult",
+protocol: '*Compiler-Inlining',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return self._expression();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"asInlinedBlockResult",{},$globals.IRBlockReturn)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "asInlinedBlockResult\x0a\x09^ self expression",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["expression"]
+}),
+$globals.IRBlockReturn);
+
+$core.addMethod(
+$core.method({
+selector: "asInlinedBlockResult",
+protocol: '*Compiler-Inlining',
+fn: function (){
+var self=this;
+return self;
+
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "asInlinedBlockResult\x0a\x09^ self",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.IRInstruction);
+
 });

+ 21 - 11
src/Compiler-Inlining.st

@@ -431,10 +431,8 @@ inlineClosure: anIRClosure
 	statements ifNotEmpty: [
 		statements allButLast do: [ :each | sequence add: each ].
 
-		"Inlined closures don't have implicit local returns"
-		(statements last isReturn and: [ statements last isBlockReturn ])
-			ifTrue: [ sequence add: statements last expression ]
-			ifFalse: [ sequence add: statements last ] ].
+		"Inlined closures change local returns into result value itself"
+		sequence add: statements last asInlinedBlockResult ].
 
 	^ inlinedClosure
 !
@@ -539,19 +537,19 @@ inlineAssignment: anIRAssignment
 !
 
 inlineClosure: anIRClosure
-	| inlinedClosure statements |
+	| closure statements |
 
-	inlinedClosure := super inlineClosure: anIRClosure.
-	statements := inlinedClosure sequence instructions.
+	closure := super inlineClosure: anIRClosure.
+	statements := closure sequence instructions.
 	
 	statements ifNotEmpty: [
-		statements last canBeAssigned ifTrue: [
+		statements last yieldsValue ifTrue: [
 			statements last replaceWith: (IRAssignment new
 				add: self assignment left;
 				add: statements last copy;
 				yourself) ] ].
 
-	^ inlinedClosure
+	^ closure
 ! !
 
 IRSendInliner subclass: #IRReturnInliner
@@ -575,8 +573,8 @@ inlineClosure: anIRClosure
 	statements := closure sequence instructions.
 	
 	statements ifNotEmpty: [
-		statements last isReturn
-			ifFalse: [ statements last replaceWith: (IRReturn new
+		statements last yieldsValue ifTrue: [
+			statements last replaceWith: (IRReturn new
 				add: statements last copy;
 				yourself)] ].
 
@@ -628,3 +626,15 @@ SemanticError subclass: #InliningError
 !InliningError commentStamp!
 Instances of InliningError are signaled when using an `InliningCodeGenerator`in a `Compiler`.!
 
+!IRBlockReturn methodsFor: '*Compiler-Inlining'!
+
+asInlinedBlockResult
+	^ self expression
+! !
+
+!IRInstruction methodsFor: '*Compiler-Inlining'!
+
+asInlinedBlockResult
+	^ self
+! !
+