Skip to content

Commit

Permalink
Both from conversions must be present in the module defining Complex …
Browse files Browse the repository at this point in the history
…type
  • Loading branch information
JaroslavTulach committed Feb 16, 2024
1 parent 0e249c0 commit a5c0674
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.AcceptsError;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.EnsoRootNode;
import org.enso.interpreter.node.callable.InteropConversionCallNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.UnresolvedConversion;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
import org.enso.interpreter.runtime.scope.ModuleScope;
import org.enso.interpreter.runtime.state.State;

@BuiltinMethod(
Expand Down Expand Up @@ -91,8 +94,8 @@ public boolean execute(
convert1 = insert(WithConversionNode.create());
convert2 = insert(WithConversionNode.create());
}
return convert1.executeThatConversion(frame, other, self)
|| convert2.executeThatConversion(frame, self, other);
return convert1.executeWithConversion(frame, other, self)
|| convert2.executeWithConversion(frame, self, other);
}
}
return areEqual;
Expand All @@ -114,7 +117,7 @@ static WithConversionNode create() {
* @return {code false} if the conversion makes no sense or result of equality check after doing
* the conversion
*/
abstract boolean executeThatConversion(VirtualFrame frame, Object self, Object that);
abstract boolean executeWithConversion(VirtualFrame frame, Object self, Object that);

static Type findType(TypeOfNode typeOfNode, Object obj) {
var rawType = typeOfNode.execute(obj);
Expand All @@ -125,15 +128,49 @@ static Type findTypeUncached(Object obj) {
return findType(TypeOfNode.getUncached(), obj);
}

record Convert(Function f1, Function f2, Function f3) {}

private static boolean isDefinedIn(ModuleScope scope, Function fn) {
if (fn.getCallTarget().getRootNode() instanceof EnsoRootNode ensoRoot) {
return ensoRoot.getModuleScope() == scope;
} else {
return false;
}
}

Convert findConversions(Type selfType, Type thatType) {
if (selfType == null || thatType == null) {
return null;
}
var ctx = EnsoContext.get(this);
var comparableType = ctx.getBuiltins().comparable().getType();

var selfScope = selfType.getDefinitionScope();

var fromSelfType =
UnresolvedConversion.build(selfScope).resolveFor(ctx, comparableType, selfType);
var fromThatType =
UnresolvedConversion.build(selfScope).resolveFor(ctx, comparableType, thatType);
var betweenBoth = UnresolvedConversion.build(selfScope).resolveFor(ctx, selfType, thatType);

if (isDefinedIn(selfScope, fromSelfType)
&& isDefinedIn(selfScope, fromThatType)
&& betweenBoth != null) {
return new Convert(fromSelfType, fromThatType, betweenBoth);
} else {
return null;
}
}

@Specialization(
limit = "3",
guards = {
"!types.hasSpecialDispatch(that)",
"selfType != null",
"thatType != null",
"selfType == findType(typeOfNode, self)",
"thatType == findType(typeOfNode, that)"
})
final boolean doThatConversionCached(
final boolean doConversionCached(
VirtualFrame frame,
Object self,
Object that,
Expand All @@ -143,22 +180,27 @@ final boolean doThatConversionCached(
Type selfType,
@Cached(value = "findType(typeOfNode, that)", uncached = "findTypeUncached(that)")
Type thatType,
@Cached("findConversions(selfType, thatType)") Convert convert,
@Shared("convert") @Cached InteropConversionCallNode convertNode,
@Shared("invoke") @Cached(allowUncached = true) EqualsSimpleNode equalityNode) {
return doDispatch(frame, self, that, thatType, convertNode, equalityNode);
if (convert == null) {
return false;
}
return doDispatch(frame, self, that, selfType, convertNode, equalityNode);
}

@Specialization(replaces = "doThatConversionCached")
final boolean doThatConversionUncached(
@Specialization(replaces = "doConversionCached")
final boolean doConversionUncached(
VirtualFrame frame,
Object self,
Object that,
@Shared("typeOf") @Cached TypeOfNode typeOfNode,
@Shared("convert") @Cached InteropConversionCallNode convertNode,
@Shared("invoke") @Cached(allowUncached = true) EqualsSimpleNode equalityNode) {
var selfType = findType(typeOfNode, self);
var thatType = findType(typeOfNode, that);
if (thatType != null) {
var result = doDispatch(frame, self, that, thatType, convertNode, equalityNode);
if (findConversions(selfType, thatType) != null) {
var result = doDispatch(frame, self, that, selfType, convertNode, equalityNode);
return result;
}
return false;
Expand All @@ -168,18 +210,18 @@ private boolean doDispatch(
VirtualFrame frame,
Object self,
Object that,
Type thatType,
Type selfType,
InteropConversionCallNode convertNode,
EqualsSimpleNode equalityNode)
throws PanicException {
var convert = UnresolvedConversion.build(thatType.getDefinitionScope());
var convert = UnresolvedConversion.build(selfType.getDefinitionScope());

var ctx = EnsoContext.get(this);
var state = State.create(ctx);
try {
var selfAsThat = convertNode.execute(convert, state, new Object[] {thatType, self});
var result = equalityNode.execute(frame, selfAsThat, that);
assert !result || assertHashCodeIsTheSame(self, selfAsThat);
var thatAsSelf = convertNode.execute(convert, state, new Object[] {selfType, that});
var result = equalityNode.execute(frame, self, thatAsSelf);
assert !result || assertHashCodeIsTheSame(self, thatAsSelf);
return result;
} catch (ArityException ex) {
var assertsOn = false;
Expand Down
1 change: 1 addition & 0 deletions test/Base_Tests/src/Data/Numbers_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Complex_Comparator
7*x.re + 11*x.im

Comparable.from (_:Complex) = Complex_Comparator
Comparable.from (_:Number) = Complex_Comparator


add_specs suite_builder =
Expand Down
2 changes: 2 additions & 0 deletions test/Base_Tests/src/Semantic/Conversion_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ add_specs suite_builder =
# no conversions needed when calling `exchange` methods
nine . should_equal one

suite_builder.group "MultiValue Conversions" group_builder->

group_builder.specify "Requesting Text & Foo" <|
check a (n : Text & Foo) = case a of
0 -> n.foo
Expand Down

0 comments on commit a5c0674

Please sign in to comment.