Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keep EnsoMultiValue as self when dispatching Any instance methods #12170

Merged
merged 13 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
parentheses. [This is now a syntax error.][11856]
- [Native libraries of projects can be added to `polyglot/lib` directory][11874]
- [Prefer module methods over `Any` instance ones][12048]
- [Keep intersection type's self when dispatching Any instance methods][12170]
- [Types without constructors can be public][12052]
- Symetric, transitive and reflexive [equality for intersection types][11897]
- [IR definitions are generated by an annotation processor][11770]
Expand All @@ -55,6 +56,7 @@
[11856]: https://github.com/enso-org/enso/pull/11856
[11874]: https://github.com/enso-org/enso/pull/11874
[12048]: https://github.com/enso-org/enso/pull/12048
[12170]: https://github.com/enso-org/enso/pull/12170
[12052]: https://github.com/enso-org/enso/pull/12052
[11897]: https://github.com/enso-org/enso/pull/11897
[11770]: https://github.com/enso-org/enso/pull/11770
Expand Down
69 changes: 23 additions & 46 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5125,34 +5125,29 @@ launcherDistributionRoot := packageBuilder.localArtifact("launcher") / "enso"
projectManagerDistributionRoot :=
packageBuilder.localArtifact("project-manager") / "enso"

lazy val createEnginePackage =
taskKey[Unit]("Creates the engine distribution package")
createEnginePackage := {
lazy val createStdLibsIndexes =
taskKey[Unit]("Creates index files for standard libraries")
createStdLibsIndexes := {
updateLibraryManifests.value
buildEngineDistributionNoIndex.value
val modulesToCopy = componentModulesPaths.value
val root = engineDistributionRoot.value
val log = streams.value.log
val cacheFactory = streams.value.cacheStoreFactory
DistributionPackage.createEnginePackage(
distributionRoot = root,
cacheFactory = cacheFactory,
log = log,
jarModulesToCopy = modulesToCopy,
graalVersion = graalMavenPackagesVersion,
javaVersion = graalVersion,
ensoVersion = ensoVersion,
editionName = currentEdition,
sourceStdlibVersion = stdLibVersion,
targetStdlibVersion = targetStdlibVersion,
targetDir = (`syntax-rust-definition` / rustParserTargetDirectory).value,
generateIndex = true
)
log.info(s"Engine package created at $root")
val modulesToCopy = componentModulesPaths.value
val distributionRoot = engineDistributionRoot.value
val log = streams.value.log
val cacheFactory = streams.value.cacheStoreFactory

DistributionPackage.indexStdLibs(
stdLibVersion = targetStdlibVersion,
ensoVersion = ensoVersion,
stdLibRoot = distributionRoot / "lib",
ensoExecutable = distributionRoot / "bin" / "enso",
cacheFactory = cacheFactory.sub("stdlib"),
log = log
)
log.info(s"Standard library indexes create for $distributionRoot")
}

ThisBuild / createEnginePackage := {
createEnginePackage.result.value
ThisBuild / createStdLibsIndexes := {
createStdLibsIndexes.result.value
}

lazy val createEnginePackageNoIndex =
Expand All @@ -5174,8 +5169,7 @@ createEnginePackageNoIndex := {
editionName = currentEdition,
sourceStdlibVersion = stdLibVersion,
targetStdlibVersion = targetStdlibVersion,
targetDir = (`syntax-rust-definition` / rustParserTargetDirectory).value,
generateIndex = false
targetDir = (`syntax-rust-definition` / rustParserTargetDirectory).value
)
log.info(s"Engine package created at $root")
}
Expand All @@ -5199,25 +5193,7 @@ buildEngineDistributionNoIndex := Def.taskIf {
// of other tasks.
ThisBuild / buildEngineDistributionNoIndex := {
updateLibraryManifests.value
val modulesToCopy = componentModulesPaths.value
val root = engineDistributionRoot.value
val log = streams.value.log
val cacheFactory = streams.value.cacheStoreFactory
DistributionPackage.createEnginePackage(
distributionRoot = root,
cacheFactory = cacheFactory,
log = log,
jarModulesToCopy = modulesToCopy,
graalVersion = graalMavenPackagesVersion,
javaVersion = graalVersion,
ensoVersion = ensoVersion,
editionName = currentEdition,
sourceStdlibVersion = stdLibVersion,
targetStdlibVersion = targetStdlibVersion,
targetDir = (`syntax-rust-definition` / rustParserTargetDirectory).value,
generateIndex = false
)
log.info(s"Engine package created at $root")
createEnginePackageNoIndex.value
}

lazy val shouldBuildNativeImage = taskKey[Boolean](
Expand Down Expand Up @@ -5256,7 +5232,8 @@ lazy val buildEngineDistribution =
taskKey[Unit]("Builds the engine distribution")
buildEngineDistribution := {
buildEngineDistributionNoIndex.value
createEnginePackage.value
createEnginePackageNoIndex.value
createStdLibsIndexes.value
}

// This makes the buildEngineDistributionNoIndex task usable as a dependency
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package org.enso.interpreter.node.expression.builtin.text;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.GenerateUncached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.data.EnsoMultiValue;
import org.enso.interpreter.runtime.data.atom.Atom;
import org.enso.interpreter.runtime.data.atom.AtomConstructor;
import org.enso.interpreter.runtime.data.atom.StructsLibrary;
Expand All @@ -33,10 +35,22 @@ Text doAtom(Atom at) {
}
}

@Specialization
Text doMultiValue(
EnsoMultiValue mv,
@Cached EnsoMultiValue.CastToNode castToNode,
@Cached AnyToTextNode toTextNode) {
var ctx = EnsoContext.get(this);
var any = ctx.getBuiltins().any();
var first = castToNode.findTypeOrNull(any, mv, false, false);
assert first != null;
return toTextNode.execute(first);
}

@Fallback
Text doOther(Object object, @CachedLibrary(limit = "5") InteropLibrary interop) {
Text doOther(Object object) {
try {
return Text.create(showObject(object, interop));
return Text.create(showObject(object));
} catch (UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
return Text.create(object.toString());
Expand All @@ -55,14 +69,14 @@ private Text doComplexAtom(Atom atom) {
Text res = Text.create("(", consName(atom.getConstructor()));
res = Text.create(res, " ");
try {
res = Text.create(res, showObject(structs.getField(atom, 0), interop));
res = Text.create(res, showObject(structs.getField(atom, 0)));
} catch (UnsupportedMessageException e) {
res = Text.create(res, structs.getField(atom, 0).toString());
}
for (int i = 1; i < atom.getConstructor().getArity(); i++) {
res = Text.create(res, " ");
try {
res = Text.create(res, showObject(structs.getField(atom, i), interop));
res = Text.create(res, showObject(structs.getField(atom, i)));
} catch (UnsupportedMessageException e) {
res = Text.create(res, structs.getField(atom, i).toString());
}
Expand All @@ -72,8 +86,7 @@ private Text doComplexAtom(Atom atom) {
}

@CompilerDirectives.TruffleBoundary
private String showObject(Object child, InteropLibrary interop)
throws UnsupportedMessageException {
private String showObject(Object child) throws UnsupportedMessageException {
if (child == null) {
// TODO [RW] This is a temporary workaround to make it possible to display errors related to
// https://www.pivotaltracker.com/story/show/181652974
Expand All @@ -82,6 +95,7 @@ private String showObject(Object child, InteropLibrary interop)
} else if (child instanceof Boolean) {
return (boolean) child ? "True" : "False";
} else {
var interop = InteropLibrary.getUncached();
return interop.asString(interop.toDisplayString(child));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -595,16 +595,21 @@ public final Object findTypeOrNull(
public final Pair<Function, Type> resolveSymbol(
MethodResolverNode node, UnresolvedSymbol symbol) {
var ctx = EnsoContext.get(node);
Pair<Function, Type> foundAnyMethod = null;
Pair<Function, Type> fallbackToAnyMethod = null;
for (var t : EnsoMultiType.AllTypesWith.getUncached().executeAllTypes(dispatch, null, 0)) {
var fnAndType = node.execute(t, symbol);
if (fnAndType != null) {
if (dispatch.typesLength() == 1 || fnAndType.getRight() != ctx.getBuiltins().any()) {
return Pair.create(fnAndType.getLeft(), t);
if (fnAndType.getRight() != ctx.getBuiltins().any()) {
// if there is a non-Any method available in any of the
// dispach types, then use it!
return fnAndType;
}
if (fallbackToAnyMethod == null) {
// remember a suitable method on Any
fallbackToAnyMethod = fnAndType;
}
foundAnyMethod = fnAndType;
}
}
return foundAnyMethod;
return fallbackToAnyMethod;
}
}
14 changes: 1 addition & 13 deletions project/DistributionPackage.scala
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,7 @@ object DistributionPackage {
editionName: String,
sourceStdlibVersion: String,
targetStdlibVersion: String,
targetDir: File,
generateIndex: Boolean
targetDir: File
): Unit = {
copyDirectoryIncremental(
file("distribution/engine/THIRD-PARTY"),
Expand Down Expand Up @@ -195,17 +194,6 @@ object DistributionPackage {
graalVersion = graalVersion,
javaVersion = javaVersion
)

if (generateIndex) {
indexStdLibs(
stdLibVersion = targetStdlibVersion,
ensoVersion = ensoVersion,
stdLibRoot = distributionRoot / "lib",
ensoExecutable = distributionRoot / "bin" / "enso",
cacheFactory = cacheFactory.sub("stdlib"),
log = log
)
}
}

def indexStdLibs(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ add_specs suite_builder =
group_builder.specify "after passing A&B value to a function expecting A argument, B becomes hidden" <|
ab = make_a_and_b
a2 = id_a ab
# checks also hidden types
a2.is_a A . should_be_true
a2.is_a B . should_be_false
a2.is_a B . should_be_true

# Passing a2 to a function expecting B fails because B part was hidden
Test.expect_panic Type_Error (id_b a2)
Expand All @@ -60,8 +61,9 @@ add_specs suite_builder =
group_builder.specify "after casting A&B to A, B part is again hidden" <|
ab = make_a_and_b
a2 = ab:A
# checks also hidden types
a2.is_a A . should_be_true
a2.is_a B . should_be_false
a2.is_a B . should_be_true

# Passing a2 to a function expecting B fails because B part was hidden
Test.expect_panic Type_Error (id_b a2)
Expand All @@ -74,8 +76,9 @@ add_specs suite_builder =
ab = make_a_and_b
b2 = id_b ab
a2 = b2:A
# checks also hidden types
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
a2.is_a A . should_be_true
a2.is_a B . should_be_false
a2.is_a B . should_be_true

a2.a_method.should_equal "A method"
Test.expect_panic No_Such_Method (a2.b_method)
Expand All @@ -84,7 +87,8 @@ add_specs suite_builder =
ab = make_a_and_b
a2 = id_a ab
b2 = a2:B
b2.is_a A . should_be_false
# checks also hidden types
b2.is_a A . should_be_true
b2.is_a B . should_be_true

Test.expect_panic No_Such_Method (b2.a_method)
Expand All @@ -98,13 +102,15 @@ add_specs suite_builder =
ab_as_a : A ->
ab_as_a.a_method . should_equal "A method"
ab_as_a.is_a A . should_be_true
ab_as_a.is_a B . should_be_false
# checks also hidden types
ab_as_a.is_a B . should_be_true
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
_ -> Test.fail "Expected ab to go to `: A` branch"

case ab of
ab_as_b : B ->
ab_as_b.b_method . should_equal "B method"
ab_as_b.is_a A . should_be_false
# checks also hidden types
ab_as_b.is_a A . should_be_true
ab_as_b.is_a B . should_be_true
_ -> Test.fail "Expected ab to go to `: B` branch"

Expand Down Expand Up @@ -141,8 +147,10 @@ add_specs suite_builder =

# We hide A&B parts by casting to C
c = abc:C
c.is_a A . should_be_false
c.is_a B . should_be_false

# is_a checks also hidden types
c.is_a A . should_be_true
c.is_a B . should_be_true
c.is_a C . should_be_true

Test.expect_panic No_Such_Method (c.a_method)
Expand Down Expand Up @@ -269,7 +277,7 @@ add_specs suite_builder =
r.a_method . should_equal "A method"
r.b_method . should_equal "B method"

group_builder.specify "calling `.catch` on an intersection type should not lose even the hidden refinements" pending=dispatch_pending <|
group_builder.specify "calling `.catch` on an intersection type should not lose even the hidden refinements" <|
ab = make_a_and_b
x = ab:A
r = x.catch Any _->"catched"
Expand All @@ -283,7 +291,7 @@ add_specs suite_builder =
y.a_method . should_equal "A method"
y.b_method . should_equal "B method"

group_builder.specify "calling `.throw_on_warning` on an intersection type should not lose even the hidden refinements" pending=dispatch_pending <|
group_builder.specify "calling `.throw_on_warning` on an intersection type should not lose even the hidden refinements" <|
ab = make_a_and_b
x = ab:A
r = x.throw_on_warning
Expand All @@ -306,7 +314,7 @@ add_specs suite_builder =
y.b_method . should_equal "B method"
Problems.expect_only_warning Illegal_State y

group_builder.specify "removing warnings from an intersection type should not lose even the hidden refinements" pending=dispatch_pending <|
group_builder.specify "removing warnings from an intersection type should not lose even the hidden refinements" <|
ab = make_a_and_b
x1 = Warning.attach (Illegal_State.Error "my warning") (ab:A)
x2 = (Warning.attach (Illegal_State.Error "my warning") ab):A
Expand Down
6 changes: 6 additions & 0 deletions test/Base_Tests/src/Semantic/Multi_Value_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ add_specs suite_builder =
c = Complex.new 1.5 0.0
(c:Complex).re . should_equal 1.5
(c:Float) . should_equal 1.5
group_builder.specify "Complex & Float remain after instance method invocation" <|
c = Complex.new 1.5 0.0 . confuse_me
(c:Complex).re . should_equal 1.5
(c:Float) . should_equal 1.5
radeusgd marked this conversation as resolved.
Show resolved Hide resolved

suite_builder.group "Chain Multi Value" group_builder->
to_b_to_c obj =
Expand Down Expand Up @@ -173,6 +177,8 @@ add_specs suite_builder =
Test.expect_panic Type_Error <|
a : C

Any.confuse_me self = self

main filter=Nothing =
suite = Test.build suite_builder->
add_specs suite_builder
Expand Down
Loading