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

Castable constraint #1954

Merged
merged 4 commits into from Nov 19, 2019
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -18,11 +18,13 @@
import com.google.common.annotations.VisibleForTesting;
This conversation was marked as resolved by dain

This comment has been minimized.

Copy link
@sopel39

sopel39 Nov 5, 2019

Member

@dain could you add to commit message what castable constraint is?

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import io.prestosql.spi.function.OperatorType;
import io.prestosql.spi.type.TypeSignature;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkArgument;
@@ -159,32 +161,52 @@ public String toString()
*/
public static TypeVariableConstraint withVariadicBound(String name, String variadicBound)
{
return new TypeVariableConstraint(name, false, false, variadicBound);
return new TypeVariableConstraint(name, false, false, variadicBound, ImmutableSet.of(), ImmutableSet.of());
}

public static TypeVariableConstraint comparableWithVariadicBound(String name, String variadicBound)
{
return new TypeVariableConstraint(name, true, false, variadicBound);
return new TypeVariableConstraint(name, true, false, variadicBound, ImmutableSet.of(), ImmutableSet.of());
}

public static TypeVariableConstraint typeVariable(String name)
{
return new TypeVariableConstraint(name, false, false, null);
return new TypeVariableConstraint(name, false, false, null, ImmutableSet.of(), ImmutableSet.of());
}

public static TypeVariableConstraint comparableTypeParameter(String name)
{
return new TypeVariableConstraint(name, true, false, null);
return new TypeVariableConstraint(name, true, false, null, ImmutableSet.of(), ImmutableSet.of());
}

public static TypeVariableConstraint orderableWithVariadicBound(String name, String variadicBound)
{
return new TypeVariableConstraint(name, false, true, variadicBound);
return new TypeVariableConstraint(name, false, true, variadicBound, ImmutableSet.of(), ImmutableSet.of());
}

public static TypeVariableConstraint orderableTypeParameter(String name)
{
return new TypeVariableConstraint(name, false, true, null);
return new TypeVariableConstraint(name, false, true, null, ImmutableSet.of(), ImmutableSet.of());
}

public static TypeVariableConstraint castableToTypeParameter(String name, TypeSignature... toType)
{
return new TypeVariableConstraint(name, false, false, null, ImmutableSet.copyOf(toType), ImmutableSet.of());
}

public static TypeVariableConstraint castableToTypeParameter(String name, Set<TypeSignature> toType)
{
return new TypeVariableConstraint(name, false, false, null, toType, ImmutableSet.of());
}

public static TypeVariableConstraint castableFromTypeParameter(String name, TypeSignature... toType)
{
return new TypeVariableConstraint(name, false, false, null, ImmutableSet.of(), ImmutableSet.copyOf(toType));
}

public static TypeVariableConstraint castableFromTypeParameter(String name, Set<TypeSignature> toType)
{
return new TypeVariableConstraint(name, false, false, null, ImmutableSet.of(), toType);
}

public static LongVariableConstraint longVariableExpression(String variable, String expression)
@@ -16,14 +16,18 @@
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import io.prestosql.spi.PrestoException;
import io.prestosql.spi.type.NamedTypeSignature;
import io.prestosql.spi.type.ParameterKind;
import io.prestosql.spi.type.RowType;
import io.prestosql.spi.type.Type;
import io.prestosql.spi.type.TypeSignature;
import io.prestosql.spi.type.TypeSignatureParameter;
import io.prestosql.sql.analyzer.TypeSignatureProvider;
import io.prestosql.type.FunctionType;
import io.prestosql.type.JsonType;
import io.prestosql.type.TypeCoercion;
import io.prestosql.type.UnknownType;

import java.util.Collections;
import java.util.HashMap;
@@ -38,6 +42,10 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Verify.verify;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static io.prestosql.metadata.SignatureBinder.RelationshipType.EXACT;
import static io.prestosql.metadata.SignatureBinder.RelationshipType.EXPLICIT_COERCION_FROM;
import static io.prestosql.metadata.SignatureBinder.RelationshipType.EXPLICIT_COERCION_TO;
import static io.prestosql.metadata.SignatureBinder.RelationshipType.IMPLICIT_COERCION;
import static io.prestosql.sql.analyzer.TypeSignatureProvider.fromTypes;
import static io.prestosql.type.TypeCalculation.calculateLiteralValue;
import static io.prestosql.type.TypeCoercion.isCovariantTypeBase;
@@ -215,7 +223,7 @@ private static void checkNoLiteralVariableUsageAcrossTypes(TypeSignature typeSig
private boolean appendConstraintSolversForReturnValue(ImmutableList.Builder<TypeConstraintSolver> resultBuilder, TypeSignatureProvider actualReturnType)
{
TypeSignature formalReturnTypeSignature = declaredSignature.getReturnType();
return appendTypeRelationshipConstraintSolver(resultBuilder, formalReturnTypeSignature, actualReturnType, false)
return appendTypeRelationshipConstraintSolver(resultBuilder, formalReturnTypeSignature, actualReturnType, EXACT)
&& appendConstraintSolvers(resultBuilder, formalReturnTypeSignature, actualReturnType, false);
}

@@ -235,7 +243,7 @@ private boolean appendConstraintSolversForArguments(ImmutableList.Builder<TypeCo
}

for (int i = 0; i < formalTypeSignatures.size(); i++) {
if (!appendTypeRelationshipConstraintSolver(resultBuilder, formalTypeSignatures.get(i), actualTypes.get(i), allowCoercion)) {
if (!appendTypeRelationshipConstraintSolver(resultBuilder, formalTypeSignatures.get(i), actualTypes.get(i), allowCoercion ? IMPLICIT_COERCION : EXACT)) {
return false;
}
}
@@ -292,6 +300,15 @@ private boolean appendConstraintSolvers(
return true;
}
Type actualType = metadata.getType(actualTypeSignatureProvider.getTypeSignature());
for (TypeSignature castToSignature : typeVariableConstraint.getCastableTo()) {
appendTypeRelationshipConstraintSolver(resultBuilder, castToSignature, actualTypeSignatureProvider, EXPLICIT_COERCION_TO);
}
for (TypeSignature castFromSignature : typeVariableConstraint.getCastableFrom()) {
appendTypeRelationshipConstraintSolver(resultBuilder, castFromSignature, actualTypeSignatureProvider, EXPLICIT_COERCION_FROM);
}
if (typeVariableConstraint.getVariadicBound() != null && !typeVariableConstraint.getVariadicBound().equalsIgnoreCase(actualType.getTypeSignature().getBase())) {
return actualType == UNKNOWN;
}
resultBuilder.add(new TypeParameterSolver(
formalTypeSignature.getBase(),
actualType,
@@ -496,13 +513,61 @@ private static TypeSignatureParameter applyBoundVariables(TypeSignatureParameter
return builder.build();
}

private boolean satisfiesCoercion(boolean allowCoercion, Type fromType, TypeSignature toTypeSignature)
private boolean satisfiesCoercion(RelationshipType relationshipType, Type actualType, TypeSignature constraintTypeSignature)
{
if (allowCoercion) {
return typeCoercion.canCoerce(fromType, metadata.getType(toTypeSignature));
switch (relationshipType) {
case EXACT:
return actualType.getTypeSignature().equals(constraintTypeSignature);
case IMPLICIT_COERCION:
return typeCoercion.canCoerce(actualType, metadata.getType(constraintTypeSignature));
case EXPLICIT_COERCION_TO:
return canCast(actualType, metadata.getType(constraintTypeSignature));
case EXPLICIT_COERCION_FROM:
return canCast(metadata.getType(constraintTypeSignature), actualType);
default:
throw new IllegalArgumentException("Unsupported relationshipType " + relationshipType);
}
else {
return fromType.getTypeSignature().equals(toTypeSignature);
}

private boolean canCast(Type fromType, Type toType)
{
if (toType instanceof UnknownType) {
return true;
}
if (fromType instanceof RowType) {
if (toType instanceof RowType) {
List<Type> fromTypeParameters = fromType.getTypeParameters();
List<Type> toTypeParameters = toType.getTypeParameters();
if (fromTypeParameters.size() != toTypeParameters.size()) {
return false;
}
for (int fieldIndex = 0; fieldIndex < fromTypeParameters.size(); fieldIndex++) {
if (!canCast(fromTypeParameters.get(fieldIndex), toTypeParameters.get(fieldIndex))) {
return false;
}
}
return true;
}
else if (toType instanceof JsonType) {
return fromType.getTypeParameters().stream()
.allMatch(fromTypeParameter -> canCast(fromTypeParameter, toType));
}
else {
return false;
}
}
if (fromType instanceof JsonType) {
if (toType instanceof RowType) {
return toType.getTypeParameters().stream()
.allMatch(toTypeParameter -> canCast(fromType, toTypeParameter));
}
}
try {
metadata.getCoercion(fromType, toType);
return true;
}
catch (PrestoException e) {
return false;
}
}

@@ -735,7 +800,7 @@ public SolverReturnStatus update(BoundVariables.Builder bindings)

ImmutableList.Builder<TypeConstraintSolver> constraintsBuilder = ImmutableList.builder();
// Coercion on function type is not supported yet.
if (!appendTypeRelationshipConstraintSolver(constraintsBuilder, formalLambdaReturnTypeSignature, new TypeSignatureProvider(actualReturnType.getTypeSignature()), false)) {
if (!appendTypeRelationshipConstraintSolver(constraintsBuilder, formalLambdaReturnTypeSignature, new TypeSignatureProvider(actualReturnType.getTypeSignature()), EXACT)) {
return SolverReturnStatus.UNSOLVABLE;
}
if (!appendConstraintSolvers(constraintsBuilder, formalLambdaReturnTypeSignature, new TypeSignatureProvider(actualReturnType.getTypeSignature()), allowCoercion)) {
@@ -783,7 +848,7 @@ private boolean appendTypeRelationshipConstraintSolver(
ImmutableList.Builder<TypeConstraintSolver> resultBuilder,
TypeSignature formalTypeSignature,
TypeSignatureProvider actualTypeSignatureProvider,
boolean allowCoercion)
RelationshipType relationshipType)
{
if (actualTypeSignatureProvider.hasDependency()) {
// Fail if the formal type is not function.
@@ -797,26 +862,26 @@ private boolean appendTypeRelationshipConstraintSolver(
typeVariables,
longVariables,
metadata.getType(actualTypeSignatureProvider.getTypeSignature()),
allowCoercion));
relationshipType));
return true;
}

private class TypeRelationshipConstraintSolver
implements TypeConstraintSolver
{
private final TypeSignature superTypeSignature;
private final TypeSignature formalTypeSignature;
private final Set<String> typeVariables;
private final Set<String> longVariables;
private final Type actualType;
private final boolean allowCoercion;
private final RelationshipType relationshipType;

public TypeRelationshipConstraintSolver(TypeSignature superTypeSignature, Set<String> typeVariables, Set<String> longVariables, Type actualType, boolean allowCoercion)
public TypeRelationshipConstraintSolver(TypeSignature formalTypeSignature, Set<String> typeVariables, Set<String> longVariables, Type actualType, RelationshipType relationshipType)
{
this.superTypeSignature = superTypeSignature;
this.formalTypeSignature = formalTypeSignature;
this.typeVariables = typeVariables;
this.longVariables = longVariables;
this.actualType = actualType;
this.allowCoercion = allowCoercion;
this.relationshipType = relationshipType;
}

@Override
@@ -833,9 +898,14 @@ public SolverReturnStatus update(BoundVariables.Builder bindings)
}
}

TypeSignature boundSignature = applyBoundVariables(superTypeSignature, bindings.build());
TypeSignature constraintTypeSignature = applyBoundVariables(formalTypeSignature, bindings.build());
This conversation was marked as resolved by dain

This comment has been minimized.

Copy link
@martint

martint Nov 18, 2019

Member

What does "formal" vs "constraint" mean in this context?


return satisfiesCoercion(allowCoercion, actualType, boundSignature) ? SolverReturnStatus.UNCHANGED_SATISFIED : SolverReturnStatus.UNCHANGED_NOT_SATISFIED;
return satisfiesCoercion(relationshipType, actualType, constraintTypeSignature) ? SolverReturnStatus.UNCHANGED_SATISFIED : SolverReturnStatus.UNCHANGED_NOT_SATISFIED;
}
}

public enum RelationshipType
{
EXACT, IMPLICIT_COERCION, EXPLICIT_COERCION_TO, EXPLICIT_COERCION_FROM
}
}
@@ -15,29 +15,44 @@

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import io.prestosql.spi.type.TypeSignature;

import javax.annotation.Nullable;

import java.util.Objects;
import java.util.Set;

import static java.util.Objects.requireNonNull;

public class TypeVariableConstraint
{
private final String name;
private final boolean comparableRequired;
private final boolean orderableRequired;
private final String variadicBound;
private final Set<TypeSignature> castableTo;
private final Set<TypeSignature> castableFrom;

@JsonCreator
public TypeVariableConstraint(
@JsonProperty("name") String name,
@JsonProperty("comparableRequired") boolean comparableRequired,
@JsonProperty("orderableRequired") boolean orderableRequired,
@JsonProperty("variadicBound") @Nullable String variadicBound)
@JsonProperty("variadicBound") @Nullable String variadicBound,
@JsonProperty("castableTo") Set<TypeSignature> castableTo,
@JsonProperty("castableFrom") Set<TypeSignature> castableFrom)
{
this.name = name;
this.comparableRequired = comparableRequired;
this.orderableRequired = orderableRequired;
this.variadicBound = variadicBound;
if (variadicBound != null && !variadicBound.equalsIgnoreCase("row")) {
throw new IllegalArgumentException("variadicBound must be row but is " + variadicBound);
}
this.castableTo = ImmutableSet.copyOf(requireNonNull(castableTo, "castableTo is null"));
this.castableFrom = ImmutableSet.copyOf(requireNonNull(castableFrom, "castableFrom is null"));
}

@JsonProperty
@@ -64,6 +79,18 @@ public String getVariadicBound()
return variadicBound;
}

@JsonProperty
public Set<TypeSignature> getCastableTo()
{
return castableTo;
}

@JsonProperty
public Set<TypeSignature> getCastableFrom()
{
return castableFrom;
}

@Override
public String toString()
{
@@ -77,6 +104,12 @@ public String toString()
if (variadicBound != null) {
value += ":" + variadicBound + "<*>";
}
if (!castableTo.isEmpty()) {
value += ":castableTo(" + Joiner.on(", ").join(castableTo) + ")";
}
if (!castableFrom.isEmpty()) {
value += ":castableFrom(" + Joiner.on(", ").join(castableFrom) + ")";
}
return value;
}

@@ -93,12 +126,14 @@ public boolean equals(Object o)
return comparableRequired == that.comparableRequired &&
orderableRequired == that.orderableRequired &&
Objects.equals(name, that.name) &&
Objects.equals(variadicBound, that.variadicBound);
Objects.equals(variadicBound, that.variadicBound) &&
Objects.equals(castableTo, that.castableTo) &&
Objects.equals(castableFrom, that.castableFrom);
}

@Override
public int hashCode()
{
return Objects.hash(name, comparableRequired, orderableRequired, variadicBound);
return Objects.hash(name, comparableRequired, orderableRequired, variadicBound, castableTo, castableFrom);
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.