Treat Boolean.False as false primitive (#6090)

Treat `Boolean.False` and `Boolean.True` as the corresponding primitives. Now, `Boolean.False == False` returns true.

# Important Notes
`False` and `True` constructs, that are converted to `ConstructorNode` during Truffle codegen, are handled specially in `ConstructorNode`. The easiest fix was to implement a similar special handling in `QualifiedAccessorNode`, although not the cleanest one.

A better solution would be to provide transformation of `Boolean.True` IR to a true literal in `ApplicationSaturation` compiler pass. But `ApplicationSaturation` pass does not handle `True`. Moreover, for our case, it is unnecessarily complicated.
This commit is contained in:
Pavel Marek 2023-03-28 05:41:49 +02:00 committed by GitHub
parent 3f7c4a47da
commit 9bec3a4e71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 29 deletions

View File

@ -4,6 +4,7 @@ import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.nodes.RootNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor; import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
@NodeInfo( @NodeInfo(
@ -36,7 +37,16 @@ public class QualifiedAccessorNode extends RootNode {
*/ */
public Object execute(VirtualFrame frame) { public Object execute(VirtualFrame frame) {
if (atomConstructor.getArity() == 0) { if (atomConstructor.getArity() == 0) {
return atomConstructor.newInstance(); var trueCtor = EnsoContext.get(this).getBuiltins().bool().getTrue();
var falseCtor = EnsoContext.get(this).getBuiltins().bool().getFalse();
// This matches the shortcuts provided in ConstructorNode
if (atomConstructor == trueCtor) {
return true;
} else if (atomConstructor == falseCtor) {
return false;
} else {
return atomConstructor.newInstance();
}
} else { } else {
return atomConstructor; return atomConstructor;
} }

View File

@ -9,15 +9,20 @@ class BooleanTest extends InterpreterTest {
interpreterContext: InterpreterContext interpreterContext: InterpreterContext
): Unit = { ): Unit = {
val defaultImports =
"""
|from Standard.Base.Data.Boolean import all
|import Standard.Base.IO
|""".stripMargin
"support if_then_else" in { "support if_then_else" in {
val code = val code =
"""from Standard.Base.Data.Boolean import all s"""$defaultImports
|import Standard.Base.IO |
| |main =
|main = | if True then IO.println "true when true" else IO.println "false when true"
| if True then IO.println "true when true" else IO.println "false when true" | if False then IO.println "true when false" else IO.println "false when false"
| if False then IO.println "true when false" else IO.println "false when false" |""".stripMargin
|""".stripMargin
eval(code) eval(code)
consumeOut shouldEqual List("true when true", "false when false") consumeOut shouldEqual List("true when true", "false when false")
} }
@ -57,32 +62,55 @@ class BooleanTest extends InterpreterTest {
"support logical AND and OR operators" in { "support logical AND and OR operators" in {
val code = val code =
"""from Standard.Base.Data.Boolean import all s"""$defaultImports
|import Standard.Base.IO |
| |main =
|main = | IO.println True&&False
| IO.println True&&False | IO.println True&&True
| IO.println True&&True | IO.println True&&Boolean.True
| IO.println False||False | IO.println False||False
| IO.println True||False | IO.println True||False
| IO.println ((True && False) || (True && True)) | IO.println ((True && False) || (True && True))
|""".stripMargin |""".stripMargin
eval(code) eval(code)
consumeOut shouldEqual List("False", "True", "False", "True", "True") consumeOut shouldEqual List(
"False",
"True",
"True",
"False",
"True",
"True"
)
} }
"support negation" in { "support negation" in {
val code = val code =
"""from Standard.Base.Data.Boolean import all s"""$defaultImports
|import Standard.Base.IO |
| |main =
|main = | IO.println True.not
| IO.println True.not | IO.println Boolean.True.not
| IO.println False.not | IO.println False.not
| IO.println (1==2 . not) | IO.println Boolean.False.not
|""".stripMargin | IO.println (1==2 . not)
|""".stripMargin
eval(code) eval(code)
consumeOut shouldEqual List("False", "True", "True") consumeOut shouldEqual List("False", "False", "True", "True", "True")
}
"literal equals atom constructor" in {
val code =
s"""$defaultImports
|
|main =
| IO.println (False == Boolean.False)
| IO.println (Boolean.False == False)
| IO.println (True == Boolean.True)
| IO.println (Boolean.True == True)
|
|""".stripMargin
eval(code)
consumeOut shouldEqual List("True", "True", "True", "True")
} }
} }
} }

View File

@ -199,7 +199,7 @@ object DistributionPackage {
path.globRecursive("*.enso").get().toSet path.globRecursive("*.enso").get().toSet
) { diff => ) { diff =>
if (diff.modified.nonEmpty) { if (diff.modified.nonEmpty) {
println(s"Generating index for ${libName} ") log.info(s"Generating index for $libName")
val command = Seq( val command = Seq(
Platform.executableFileName(ensoExecutable.toString), Platform.executableFileName(ensoExecutable.toString),
"--no-compile-dependencies", "--no-compile-dependencies",