Use TypeOfNode.findAllTypes to get all types associated with a value

This commit is contained in:
Jaroslav Tulach 2024-11-21 14:21:45 +01:00
parent abf68c0372
commit 87e738b779
4 changed files with 107 additions and 34 deletions

View File

@ -68,6 +68,7 @@ public final class EnsoMultiValue extends EnsoObject {
return types[0]; return types[0];
} }
@ExportMessage
public final Type[] allTypes() { public final Type[] allTypes() {
return types.clone(); return types.clone();
} }

View File

@ -166,6 +166,7 @@ public final class Type extends EnsoObject {
* @param ctx contexts to get Any type (common super class) from * @param ctx contexts to get Any type (common super class) from
* @return a compilation constant array with all types this type represents * @return a compilation constant array with all types this type represents
*/ */
@ExportMessage.Ignore
public final Type[] allTypes(EnsoContext ctx) { public final Type[] allTypes(EnsoContext ctx) {
var types = new Type[3]; var types = new Type[3];
var realCount = fillInTypes(this, types, ctx); var realCount = fillInTypes(this, types, ctx);

View File

@ -50,7 +50,12 @@ public abstract class TypeOfNode extends Node {
* @return either {@link Type} of the value or {@link DataflowError} if there is no such type * @return either {@link Type} of the value or {@link DataflowError} if there is no such type
*/ */
public final Object findTypeOrError(Object value) { public final Object findTypeOrError(Object value) {
return executeSingleType(value); try {
var types = executeTypes(value);
return types[0];
} catch (NonTypeResult plain) {
return plain.result;
}
} }
/** /**
@ -64,58 +69,90 @@ public abstract class TypeOfNode extends Node {
return findTypeOrError(value) instanceof Type type ? type : null; return findTypeOrError(value) instanceof Type type ? type : null;
} }
abstract Object executeSingleType(Object value); /**
* Finds all types associated with a given {@code value} or returns {@code null}. It is guaranteed
* that the returned array is going to have at least one element, if it is non-{@code null}.
*
* @param value the value to check
* @return either types associated with the value or {@code null} if there is no such type
*/
public final Type[] findAllTypes(Object value) {
try {
var types = executeTypes(value);
assert types != null && types.length > 0;
return types;
} catch (NonTypeResult ex) {
return null;
}
}
/** Creates new optimizing instance of this node. */ /**
* Internal implementation call to delegate to various {@link Specialization} methods.
*
* @param value the value to find type for
* @return array of types with at least one element, but possibly more
* @throws NonTypeResult when there is a <em>interop value</em> result, but it is not a {@link
* Type}
*/
abstract Type[] executeTypes(Object value) throws NonTypeResult;
/**
* Creates new optimizing instance of this node.
*
* @return new instance of this node ready to be <em>specialized</em>
*/
@NeverDefault @NeverDefault
public static TypeOfNode create() { public static TypeOfNode create() {
return TypeOfNodeGen.create(); return TypeOfNodeGen.create();
} }
/** Returns default, non-optimizing implementation of this node. */ /**
* Returns default, non-optimizing implementation of this node.
*
* @return shared singleton instance of this node
*/
@NeverDefault @NeverDefault
public static TypeOfNode getUncached() { public static TypeOfNode getUncached() {
return TypeOfNodeGen.getUncached(); return TypeOfNodeGen.getUncached();
} }
@Specialization private static Type[] fromType(Type single) {
Object doUnresolvedSymbol(UnresolvedSymbol value) { return new Type[] {single};
return EnsoContext.get(this).getBuiltins().function();
} }
@Specialization @Specialization
Object doDouble(double value) { Type[] doUnresolvedSymbol(UnresolvedSymbol value) {
return EnsoContext.get(this).getBuiltins().number().getFloat(); return fromType(EnsoContext.get(this).getBuiltins().function());
} }
@Specialization @Specialization
Object doLong(long value) { Type[] doDouble(double value) {
return EnsoContext.get(this).getBuiltins().number().getInteger(); return fromType(EnsoContext.get(this).getBuiltins().number().getFloat());
} }
@Specialization @Specialization
Object doBigInteger(EnsoBigInteger value) { Type[] doLong(long value) {
return EnsoContext.get(this).getBuiltins().number().getInteger(); return fromType(EnsoContext.get(this).getBuiltins().number().getInteger());
} }
@Specialization @Specialization
Object doPanicException(PanicException value) { Type[] doBigInteger(EnsoBigInteger value) {
return EnsoContext.get(this).getBuiltins().panic(); return fromType(EnsoContext.get(this).getBuiltins().number().getInteger());
} }
@Specialization @Specialization
Object doPanicSentinel(PanicSentinel value) { Type[] doPanicException(PanicException value) {
return EnsoContext.get(this).getBuiltins().panic(); return fromType(EnsoContext.get(this).getBuiltins().panic());
} }
@Specialization @Specialization
Object doWarning(WithWarnings value, @Cached TypeOfNode withoutWarning) { Type[] doPanicSentinel(PanicSentinel value) {
return withoutWarning.executeSingleType(value.getValue()); return fromType(EnsoContext.get(this).getBuiltins().panic());
} }
@Specialization @Specialization
Object doEnsoMultiValue(EnsoMultiValue value) { Type[] doWarning(WithWarnings value, @Cached TypeOfNode withoutWarning) throws NonTypeResult {
return value.allTypes()[0]; return withoutWarning.executeTypes(value.getValue());
} }
static boolean isWithType(Object value, TypesLibrary types, InteropLibrary iop) { static boolean isWithType(Object value, TypesLibrary types, InteropLibrary iop) {
@ -139,32 +176,40 @@ public abstract class TypeOfNode extends Node {
} }
@Specialization(guards = {"isWithoutType(value, types)"}) @Specialization(guards = {"isWithoutType(value, types)"})
Object withoutType( Type[] withoutType(
Object value, Object value,
@Shared("interop") @CachedLibrary(limit = "3") InteropLibrary interop, @Shared("interop") @CachedLibrary(limit = "3") InteropLibrary interop,
@Shared("types") @CachedLibrary(limit = "3") TypesLibrary types, @Shared("types") @CachedLibrary(limit = "3") TypesLibrary types,
@Cached WithoutType delegate) { @Cached WithoutType delegate)
var type = WithoutType.Interop.resolve(value, interop); throws NonTypeResult {
return delegate.execute(type, value); var kind = WithoutType.Interop.resolve(value, interop);
var typeOrPlain = delegate.execute(kind, value);
if (typeOrPlain instanceof Type type) {
return fromType(type);
} else {
throw new NonTypeResult(typeOrPlain);
}
} }
@Specialization(guards = {"isWithType(value, types, interop)"}) @Specialization(guards = {"isWithType(value, types, interop)"})
Object doType( Type[] doType(
Object value, Object value,
@Shared("interop") @CachedLibrary(limit = "3") InteropLibrary interop, @Shared("interop") @CachedLibrary(limit = "3") InteropLibrary interop,
@Shared("types") @CachedLibrary(limit = "3") TypesLibrary types) { @Shared("types") @CachedLibrary(limit = "3") TypesLibrary types) {
return types.getType(value); return types.allTypes(value);
} }
@Fallback @Fallback
@CompilerDirectives.TruffleBoundary @CompilerDirectives.TruffleBoundary
Object doAny(Object value) { Type[] doAny(Object value) throws NonTypeResult {
return DataflowError.withDefaultTrace( var err =
EnsoContext.get(this) DataflowError.withDefaultTrace(
.getBuiltins() EnsoContext.get(this)
.error() .getBuiltins()
.makeCompileError("unknown type_of for " + value), .error()
this); .makeCompileError("unknown type_of for " + value),
this);
throw new NonTypeResult(err);
} }
@GenerateUncached @GenerateUncached
@ -352,4 +397,17 @@ public abstract class TypeOfNode extends Node {
} }
} }
} }
static final class NonTypeResult extends Exception {
final Object result;
NonTypeResult(Object result) {
this.result = result;
}
@Override
public Throwable fillInStackTrace() {
return this;
}
}
} }

View File

@ -68,4 +68,17 @@ public abstract class TypesLibrary extends Library {
public Type getType(Object receiver) { public Type getType(Object receiver) {
return null; return null;
} }
/**
* Returns all the receiver types. Default implementation delegates to {@link
* #getType(java.lang.Object)} and returns array with one element of that type
*
* @param receiver the typed object
* @return the corresponding types for the {@code receiver}
*/
public Type[] allTypes(Object receiver) {
var t = getType(receiver);
assert t != null : "null type for " + receiver;
return new Type[] {t};
}
} }