Skip to content

Commit

Permalink
compiler and runtime tests for generic and inner types, plus fixes #135
Browse files Browse the repository at this point in the history
  • Loading branch information
bergmanngabor committed Apr 14, 2024
1 parent 89f8ab5 commit eb8dce2
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.eclipse.viatra.query.patternlanguage.emf.types.BottomTypeKey;
import org.eclipse.viatra.query.patternlanguage.emf.types.EMFTypeInferrer;
import org.eclipse.viatra.query.patternlanguage.emf.types.EMFTypeSystem;
import org.eclipse.viatra.query.patternlanguage.emf.types.ITypeInferrer;
import org.eclipse.viatra.query.patternlanguage.emf.vql.AggregatedValue;
import org.eclipse.viatra.query.patternlanguage.emf.vql.BoolValue;
import org.eclipse.viatra.query.patternlanguage.emf.vql.CallableRelation;
Expand Down Expand Up @@ -63,7 +64,6 @@
import org.eclipse.viatra.query.runtime.matchers.ViatraQueryRuntimeException;
import org.eclipse.viatra.query.runtime.matchers.aggregators.count;
import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
import org.eclipse.viatra.query.runtime.matchers.context.common.JavaTransitiveInstancesKey;
import org.eclipse.viatra.query.runtime.matchers.util.Preconditions;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
Expand Down Expand Up @@ -169,7 +169,7 @@ private void preprocessParameters(PatternModelAcceptor<?> acceptor) {
acceptor.acceptTypeConstraint(ImmutableList.of(variable.getName()), inputKey);
} else if (variable.getType() instanceof JavaType) {
JvmDeclaredType classRef = ((JavaType) variable.getType()).getClassRef();
IInputKey inputKey = new JavaTransitiveInstancesKey(classRef.getIdentifier());
IInputKey inputKey = ITypeInferrer.jvmTypeToInputKey(classRef);
acceptor.acceptTypeCheckConstraint(ImmutableList.of(variable.getName()), inputKey);
}
}
Expand Down Expand Up @@ -365,8 +365,8 @@ private void gatherClassifierConstraint(EClassifierConstraint constraint, Patter

private void gatherTypeConstraint(TypeCheckConstraint constraint, PatternModelAcceptor<?> acceptor) {
String variableName = getVariableName(constraint.getVar(), acceptor);
String className = ((JavaType)constraint.getType()).getClassRef().getIdentifier();
IInputKey inputKey = new JavaTransitiveInstancesKey(className);
JvmDeclaredType classRef = ((JavaType)constraint.getType()).getClassRef();
IInputKey inputKey = ITypeInferrer.jvmTypeToInputKey(classRef);
acceptor.acceptTypeCheckConstraint(ImmutableList.of(variableName), inputKey);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public IInputKey getDeclaredType(Expression ex) {
List<JvmType> returnTypes = AggregatorUtil.getReturnTypes(((AggregatedValue) ex).getAggregator());
if (returnTypes.size() == 1) {
JvmType jvmType = returnTypes.get(0);
return new JavaTransitiveInstancesKey(jvmType.getIdentifier());
return ITypeInferrer.jvmTypeToInputKey(jvmType);
}
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class EMFTypeSystem extends AbstractTypeSystem {
} else if (type instanceof ReferenceType) {
return type.refname?.EType.classifierToInputKey
} else if (type instanceof JavaType) {
return new JavaTransitiveInstancesKey(type.classRef.identifier)
return ITypeInferrer.jvmTypeToInputKey(type.classRef)
}
// Never executed
throw new UnsupportedOperationException()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import org.eclipse.viatra.query.patternlanguage.emf.vql.Expression;
import org.eclipse.viatra.query.patternlanguage.emf.vql.Variable;
import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
import org.eclipse.viatra.query.runtime.matchers.context.common.JavaTransitiveInstancesKey;
import org.eclipse.xtext.common.types.JvmIdentifiableElement;
import org.eclipse.xtext.common.types.JvmTypeReference;

/**
Expand Down Expand Up @@ -67,4 +69,12 @@ public interface ITypeInferrer {
* @since 1.3
*/
JvmTypeReference getJvmType(Expression ex, EObject context);

/**
* Helper method that embeds a JVM type or type reference into an input key
* @since 2.9
*/
public static IInputKey jvmTypeToInputKey(JvmIdentifiableElement jvmType) {
return new JavaTransitiveInstancesKey(jvmType.getIdentifier(), jvmType.getQualifiedName('.'));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,39 @@
package org.eclipse.viatra.query.patternlanguage.emf.types

import com.google.inject.Inject
import java.util.HashSet
import java.util.List
import java.util.logging.Logger
import org.eclipse.viatra.query.patternlanguage.emf.helper.PatternLanguageHelper
import org.eclipse.viatra.query.patternlanguage.emf.types.judgements.ConditionalJudgement
import org.eclipse.viatra.query.patternlanguage.emf.types.judgements.ParameterTypeJudgement
import org.eclipse.viatra.query.patternlanguage.emf.types.judgements.TypeConformJudgement
import org.eclipse.viatra.query.patternlanguage.emf.types.judgements.TypeJudgement
import org.eclipse.viatra.query.patternlanguage.emf.types.judgements.XbaseExpressionTypeJudgement
import org.eclipse.viatra.query.patternlanguage.emf.util.AggregatorUtil
import org.eclipse.viatra.query.patternlanguage.emf.vql.AggregatedValue
import org.eclipse.viatra.query.patternlanguage.emf.vql.BoolValue
import org.eclipse.viatra.query.patternlanguage.emf.vql.CheckConstraint
import org.eclipse.viatra.query.patternlanguage.emf.vql.CompareConstraint
import org.eclipse.viatra.query.patternlanguage.emf.vql.CompareFeature
import org.eclipse.viatra.query.patternlanguage.emf.vql.Expression
import org.eclipse.viatra.query.patternlanguage.emf.vql.FunctionEvaluationValue
import org.eclipse.viatra.query.patternlanguage.emf.vql.JavaConstantValue
import org.eclipse.viatra.query.patternlanguage.emf.vql.JavaType
import org.eclipse.viatra.query.patternlanguage.emf.vql.ListValue
import org.eclipse.viatra.query.patternlanguage.emf.vql.NumberValue
import org.eclipse.viatra.query.patternlanguage.emf.vql.PathExpressionConstraint
import org.eclipse.viatra.query.patternlanguage.emf.vql.Pattern
import org.eclipse.viatra.query.patternlanguage.emf.vql.PatternCall
import org.eclipse.viatra.query.patternlanguage.emf.vql.PatternCompositionConstraint
import org.eclipse.viatra.query.patternlanguage.emf.vql.StringValue
import org.eclipse.viatra.query.patternlanguage.emf.vql.TypeCheckConstraint
import org.eclipse.viatra.query.patternlanguage.emf.types.judgements.ConditionalJudgement
import org.eclipse.viatra.query.patternlanguage.emf.types.judgements.ParameterTypeJudgement
import org.eclipse.viatra.query.patternlanguage.emf.types.judgements.TypeConformJudgement
import org.eclipse.viatra.query.patternlanguage.emf.types.judgements.TypeJudgement
import org.eclipse.viatra.query.patternlanguage.emf.types.judgements.XbaseExpressionTypeJudgement
import org.eclipse.viatra.query.patternlanguage.emf.util.AggregatorUtil
import org.eclipse.viatra.query.patternlanguage.emf.vql.UnaryTypeConstraint
import org.eclipse.viatra.query.patternlanguage.emf.vql.ValueReference
import org.eclipse.viatra.query.patternlanguage.emf.vql.VariableReference
import org.eclipse.viatra.query.runtime.matchers.context.common.JavaTransitiveInstancesKey
import org.eclipse.xtext.xbase.typesystem.IBatchTypeResolver
import org.eclipse.viatra.query.patternlanguage.emf.vql.JavaType
import org.eclipse.xtext.xbase.typesystem.computation.NumberLiterals
import org.eclipse.viatra.query.patternlanguage.emf.vql.NumberValue
import java.util.HashSet
import org.eclipse.viatra.query.patternlanguage.emf.vql.VariableReference
import org.eclipse.viatra.query.patternlanguage.emf.vql.ValueReference
import org.eclipse.viatra.query.patternlanguage.emf.vql.UnaryTypeConstraint
import org.eclipse.viatra.query.patternlanguage.emf.vql.JavaConstantValue

/**
* @author Zoltan Ujhelyi
Expand Down Expand Up @@ -171,7 +171,7 @@ class PatternLanguageTypeRules {
return
}
val returnType = (returnTypes).get(0)
information.provideType(new TypeJudgement(reference, new JavaTransitiveInstancesKey(returnType.identifier)))
information.provideType(new TypeJudgement(reference, ITypeInferrer.jvmTypeToInputKey(returnType)))
} else {
if (values.size !== 1 || !AggregatorUtil.mustHaveAggregatorVariables(reference)) {
//Incorrect aggregation; reported separately
Expand All @@ -195,17 +195,17 @@ class PatternLanguageTypeRules {
for (var i=0; i < returnTypes.size; i++) {
information.provideType(new ConditionalJudgement(
reference,
new JavaTransitiveInstancesKey(returnTypes.get(i).identifier),
ITypeInferrer.jvmTypeToInputKey(returnTypes.get(i)),
callParameters.get(index),
new JavaTransitiveInstancesKey(parameterTypes.get(i).identifier)
ITypeInferrer.jvmTypeToInputKey(parameterTypes.get(i))
))
// If return types are not unique for each source type, do not provide backward conditions
if (returnTypeUnique) {
information.provideType(new ConditionalJudgement(
callParameters.get(index),
new JavaTransitiveInstancesKey(parameterTypes.get(i).identifier),
ITypeInferrer.jvmTypeToInputKey(parameterTypes.get(i)),
reference,
new JavaTransitiveInstancesKey(returnTypes.get(i).identifier)
ITypeInferrer.jvmTypeToInputKey(returnTypes.get(i))
))
}
}
Expand Down Expand Up @@ -245,8 +245,11 @@ class PatternLanguageTypeRules {
* @since 2.7
*/
def dispatch void inferTypes(JavaConstantValue reference, TypeInformation information) {
val type = new JavaTransitiveInstancesKey(reference.fieldRef.type.type.identifier)
information.provideType(new TypeJudgement(reference, type))
val fieldRef = reference.fieldRef
if (null != fieldRef) {
val type = ITypeInferrer.jvmTypeToInputKey(fieldRef.type.type)
information.provideType(new TypeJudgement(reference, type))
}
}

def dispatch void inferTypes(FunctionEvaluationValue reference, TypeInformation information) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,9 @@ public IInputKey getExpressionType() {
} else if (this.unwind) {
return getComponentTypeKey(expressionType);
} else {
return new JavaTransitiveInstancesKey(expressionType.getWrapperTypeIfPrimitive().getJavaIdentifier());
return asInputKey(expressionType);
}
}

private JavaTransitiveInstancesKey getComponentTypeKey(LightweightTypeReference typeRef) {
for (LightweightTypeReference parent : typeRef.getAllSuperTypes()) {
if (parent.getRawTypeReference().isType(Set.class) && parent instanceof ParameterizedTypeReference) {
Expand All @@ -71,14 +70,18 @@ private JavaTransitiveInstancesKey getComponentTypeKey(LightweightTypeReference
if (typeArguments.size() != 1)
continue;
final LightweightTypeReference componentTypeRef = typeArguments.get(0);
final String componentJavaId = componentTypeRef.getWrapperTypeIfPrimitive().getJavaIdentifier();
return new JavaTransitiveInstancesKey(componentJavaId);
return asInputKey(componentTypeRef);
}
}

return new JavaTransitiveInstancesKey(Object.class);
}

private JavaTransitiveInstancesKey asInputKey(LightweightTypeReference typeRef) {
LightweightTypeReference jvmType = typeRef.getWrapperTypeIfPrimitive().getRawTypeReference();
return new JavaTransitiveInstancesKey(jvmType.getJavaIdentifier(), jvmType.getHumanReadableName());
}

@Override
public int hashCode() {
final int prime = 31;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,43 @@ public class JavaTransitiveInstancesKey extends BaseInputKeyWrapper<String> {
* Same as {@link #cachedOriginalInstanceClass}, but primitive classes are replaced with their wrapper classes (e.g. int --> java.lang.Integer).
*/
private Class<?> cachedWrapperInstanceClass;

/**
* Use this name to refer to the String in Java code
*/
private final String nameInJavaCode;

/**
* Preferred constructor.
* Call this constructor only in contexts where the class itself is not available for loading, e.g. it has not yet been compiled.
* @since 2.9
* @param jvmClassName {@link Class#getName()}
* @param javaClassName {@link Class#getCanonicalName()}
*/
public JavaTransitiveInstancesKey(String jvmClassName, String javaClassName) {
super(jvmClassName);
this.nameInJavaCode = javaClassName;
}

/**
* Convenience constructor for the case where the JVM Class is available
* (already precompiled and loaded)
* in the context where this input key is built.
*/
public JavaTransitiveInstancesKey(Class<?> instanceClass) {
this(primitiveTypeToWrapperClass(instanceClass).getName());
this(
primitiveTypeToWrapperClass(instanceClass).getName(),
primitiveTypeToWrapperClass(instanceClass).getCanonicalName()
);
this.cachedOriginalInstanceClass = instanceClass;
}

/**
* Call this constructor only in contexts where the class itself is not available for loading, e.g. it has not yet been compiled.
* Call this constructor only as a last resort, if the Java canonical name of the class is unavailable.
* @deprecated as of 2.9
*/
public JavaTransitiveInstancesKey(String className) {
super(className);
public JavaTransitiveInstancesKey(String jvmClassName) {
this(jvmClassName, jvmClassName.replace('$', '.'));
}


/**
* Returns null if class cannot be loaded.
Expand Down Expand Up @@ -113,8 +134,7 @@ private void resolveClassInternal() throws ClassNotFoundException {

@Override
public String getPrettyPrintableName() {
getWrapperInstanceClass();
return cachedWrapperInstanceClass == null ? wrappedKey == null ? "<null>" : wrappedKey : cachedWrapperInstanceClass.getCanonicalName();
return this.nameInJavaCode;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*******************************************************************************
* Copyright (c) 2010-2024, BergmannG, IncQuery Labs
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-v20.html.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.viatra.query.patternlanguage.emf.tests.generator

import org.junit.rules.TestName
import org.junit.Rule
import org.junit.Test

class TypingEdgeCasesCompilerTest extends AbstractQueryCompilerTest {
static val TEST_PROJECT_NAME_PREFIX = "org.eclipse.viatra.query.test"


static val TEST_CONTENTS_GENERIC = '''
package test
import "http://www.eclipse.org/emf/2002/Ecore"
pattern foo(e: java ^java.util.Map, u: java Integer) {
e == eval(^java.util.Collections.singletonMap(1,2));
u == 4;
}
'''


static val TEST_CONTENTS_INNERCLASS = '''
package test
import "http://www.eclipse.org/emf/2002/Ecore"
pattern bar(e: java ^org.eclipse.emf.ecore.EcorePackage.Literals, u: java Integer) {
e == eval(null as org.eclipse.emf.ecore.EcorePackage.Literals);
u == 4;
}
'''


static val TEST_CONTENTS_GENERIC_INNERCLASS = '''
package test
import "http://www.eclipse.org/emf/2002/Ecore"
pattern baz(e: java ^java.util.Map.Entry, u: java Integer) {
e == eval(^java.util.Collections.singletonMap(1,2).entrySet.head);
u == 4;
}
'''

static val TEST_CONTENTS_GENERIC_INNERCLASS_INFERRED = '''
package test
import "http://www.eclipse.org/emf/2002/Ecore"
pattern bang(e, u: java Integer) {
e == eval(^java.util.Collections.singletonMap(1,2).entrySet.head);
u == 4;
}
'''
static val TEST_CONTENTS_JAVACONST_INNERCLASS = '''
package test
import "http://www.eclipse.org/emf/2002/Ecore"
pattern fee(e: java org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint.BackendRequirement, u: java Integer) {
e == java org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint.BackendRequirement::SPECIFIC;
u == 4;
}
'''
static val TEST_CONTENTS_JAVACONST_INNERCLASS_INFERRED = '''
package test
import "http://www.eclipse.org/emf/2002/Ecore"
pattern fie(e, u: java Integer) {
e == java org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint.BackendRequirement::SPECIFIC;
u == 4;
}
'''


@Rule
public val name = new TestName

override String calculateTestProjectName() {
TEST_PROJECT_NAME_PREFIX + "." + name.methodName
}

@Test
def void compileGenericClass() {
testFileCreationAndBuild(TEST_CONTENTS_GENERIC, 0)
}
@Test
def void compileInnerClass() {
testFileCreationAndBuild(TEST_CONTENTS_INNERCLASS, 0)
}
@Test
def void compileGenericInnerClass() {
testFileCreationAndBuild(TEST_CONTENTS_GENERIC_INNERCLASS, 0)
}
@Test
def void compileGenericInnerClassInferred() {
testFileCreationAndBuild(TEST_CONTENTS_GENERIC_INNERCLASS_INFERRED, 0)
}
@Test
def void compileJavaconstInnerClass() {
testFileCreationAndBuild(TEST_CONTENTS_JAVACONST_INNERCLASS, 0)
}
@Test
def void compileJavaconstInnerClassInferred() {
testFileCreationAndBuild(TEST_CONTENTS_JAVACONST_INNERCLASS_INFERRED, 0)
}
}
Loading

0 comments on commit eb8dce2

Please sign in to comment.