Pārlūkot izejas kodu

Merge pull request #991 from Yakindu/type_inferrer_fixes

Fixed inference of type parameters and generic event types.
Andreas Mülder 9 gadi atpakaļ
vecāks
revīzija
3f9404e2c3

+ 16 - 2
plugins/org.yakindu.base.expressions/src/org/yakindu/base/expressions/inferrer/ExpressionsTypeInferrer.java

@@ -16,6 +16,7 @@ import static org.yakindu.base.types.typesystem.ITypeSystem.NULL;
 import static org.yakindu.base.types.typesystem.ITypeSystem.REAL;
 import static org.yakindu.base.types.typesystem.ITypeSystem.STRING;
 import static org.yakindu.base.types.typesystem.ITypeSystem.VOID;
+import static org.yakindu.base.types.typesystem.ITypeSystem.ANY;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -56,6 +57,7 @@ import org.yakindu.base.types.Parameter;
 import org.yakindu.base.types.Property;
 import org.yakindu.base.types.Type;
 import org.yakindu.base.types.TypeAlias;
+import org.yakindu.base.types.TypeParameter;
 import org.yakindu.base.types.TypeSpecifier;
 import org.yakindu.base.types.inferrer.AbstractTypeSystemInferrer;
 
@@ -206,7 +208,16 @@ public class ExpressionsTypeInferrer extends AbstractTypeSystemInferrer implemen
 			EList<Expression> args = e.getArgs();
 			inferParameter(parameters, args);
 		}
-		return inferTypeDispatch(e.getFeature());
+		InferenceResult result = inferTypeDispatch(e.getFeature());
+		if (result != null && result.getType() instanceof TypeParameter) {
+			InferenceResult ownerResult = inferTypeDispatch(e.getOwner());
+			if (ownerResult.getBindings().isEmpty()) {
+				result = getResultFor(ANY);
+			} else {
+				result = InferenceResult.from(ownerResult.getBindings().get(0).getType(), ownerResult.getBindings().get(0).getBindings());
+			}
+		}
+		return result;
 	}
 
 	public InferenceResult infer(ElementReferenceExpression e) {
@@ -283,7 +294,10 @@ public class ExpressionsTypeInferrer extends AbstractTypeSystemInferrer implemen
 		List<InferenceResult> bindings = new ArrayList<>();
 		EList<TypeSpecifier> arguments = specifier.getTypeArguments();
 		for (TypeSpecifier typeSpecifier : arguments) {
-			bindings.add(inferTypeDispatch(typeSpecifier));
+			InferenceResult binding = inferTypeDispatch(typeSpecifier);
+			if (binding != null) {
+				bindings.add(binding);
+			}
 		}
 		return InferenceResult.from(inferTypeDispatch(specifier.getType()).getType(), bindings);
 

+ 8 - 2
plugins/org.yakindu.base.types/src/org/yakindu/base/types/typesystem/GenericTypeSystem.java

@@ -21,7 +21,6 @@ import com.google.inject.Singleton;
 public class GenericTypeSystem extends AbstractTypeSystem {
 	
 	private static final GenericTypeSystem INSTANCE = new GenericTypeSystem();
-
 	
 	protected GenericTypeSystem() {}
 	
@@ -36,10 +35,17 @@ public class GenericTypeSystem extends AbstractTypeSystem {
 		declarePrimitive(INTEGER);
 		declarePrimitive(BOOLEAN);
 		declarePrimitive(VOID);
+
 		declarePrimitive(NULL);
+		getType(NULL).setAbstract(true);
 
+		declarePrimitive(ANY);
+		getType(ANY).setAbstract(true);
+		
+		declareSuperType(getType(ANY), getType(STRING));
+		declareSuperType(getType(ANY), getType(BOOLEAN));
+		declareSuperType(getType(ANY), getType(INTEGER));
 		declareSuperType(getType(INTEGER), getType(REAL));
 
-		getType(NULL).setAbstract(true);
 	}
 }

+ 1 - 0
plugins/org.yakindu.base.types/src/org/yakindu/base/types/typesystem/ITypeSystem.java

@@ -32,6 +32,7 @@ public interface ITypeSystem {
 	public static final String BOOLEAN = "boolean";
 	public static final String VOID = "void";
 	public static final String NULL = "null";
+	public static final String ANY = "any";
 
 	public Collection<Type> getTypes();
 

+ 14 - 14
plugins/org.yakindu.sct.model.stext/src/org/yakindu/sct/model/stext/inferrer/STextTypeInferrer.java

@@ -41,13 +41,13 @@ public class STextTypeInferrer extends ExpressionsTypeInferrer {
 	public static final String MISSING_VALUE = "Need to assign a value to an event of type %s.";
 
 	public InferenceResult infer(VariableDefinition e) {
-		InferenceResult type = inferTypeDispatch(e.getTypeSpecifier());
-		assertNotType(type, VARIABLE_VOID_TYPE, getResultFor(VOID));
+		InferenceResult result = inferTypeDispatch(e.getTypeSpecifier());
+		assertNotType(result, VARIABLE_VOID_TYPE, getResultFor(VOID));
 		if (e.getInitialValue() == null)
-			return type;
-		InferenceResult type2 = inferTypeDispatch(e.getInitialValue());
-		assertAssignable(type, type2, String.format(VARIABLE_DEFINITION, type2, type));
-		return type;
+			return result;
+		InferenceResult result2 = inferTypeDispatch(e.getInitialValue());
+		assertAssignable(result, result2, String.format(VARIABLE_DEFINITION, result2, result));
+		return result;
 	}
 
 	
@@ -59,15 +59,15 @@ public class STextTypeInferrer extends ExpressionsTypeInferrer {
 	}
 
 	public InferenceResult infer(Guard e) {
-		InferenceResult type = inferTypeDispatch(e.getExpression());
-		assertIsSubType(type, getResultFor(BOOLEAN), GUARD);
-		return inferTypeDispatch(type.getType());
+		InferenceResult result = inferTypeDispatch(e.getExpression());
+		assertIsSubType(result, getResultFor(BOOLEAN), GUARD);
+		return result;
 	}
 
 	public InferenceResult infer(TimeEventSpec e) {
-		InferenceResult type = inferTypeDispatch(e.getValue());
-		assertIsSubType(type, getResultFor(INTEGER), TIME_SPEC);
-		return inferTypeDispatch(type.getType());
+		InferenceResult result = inferTypeDispatch(e.getValue());
+		assertIsSubType(result, getResultFor(INTEGER), TIME_SPEC);
+		return inferTypeDispatch(result.getType());
 	}
 
 	public InferenceResult infer(Scope scope) {
@@ -85,7 +85,7 @@ public class STextTypeInferrer extends ExpressionsTypeInferrer {
 		Event event = deresolve(e.getEvent());
 		InferenceResult eventType = null;
 		if(event != null)
-			eventType = inferTypeDispatch(event.getType());
+			eventType = inferTypeDispatch(event.getTypeSpecifier());
 		eventType = eventType != null ? eventType : getResultFor(VOID);
 		if (e.getValue() == null) {
 			assertSame(eventType, getResultFor(VOID), String.format(MISSING_VALUE, eventType));
@@ -93,7 +93,7 @@ public class STextTypeInferrer extends ExpressionsTypeInferrer {
 		}
 		InferenceResult valueType = inferTypeDispatch(e.getValue());
 		assertAssignable(eventType, valueType, String.format(EVENT_DEFINITION, valueType, eventType));
-		return inferTypeDispatch(e.getValue());
+		return valueType;
 
 	}
 

+ 18 - 0
test-plugins/org.yakindu.sct.model.stext.test/src/org/yakindu/sct/model/stext/test/TypeInferrerTest.java

@@ -16,6 +16,8 @@ import org.eclipse.xtext.junit4.InjectWith;
 import org.eclipse.xtext.junit4.XtextRunner;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.yakindu.base.expressions.expressions.Expression;
+import org.yakindu.base.types.inferrer.ITypeSystemInferrer.InferenceResult;
 import org.yakindu.sct.model.stext.stext.EventRaisingExpression;
 import org.yakindu.sct.model.stext.stext.VariableDefinition;
 import org.yakindu.sct.model.stext.test.util.AbstractTypeInferrerTest;
@@ -747,4 +749,20 @@ public class TypeInferrerTest extends AbstractTypeInferrerTest {
 
 		expectIssue(inferType("(true) ? 4 : false"), "Could not determine a common type for integer and boolean.");
 	}
+	
+	@Test
+	public void testParameterizedType() {
+		assertTrue(isIntegerType(
+				inferTypeResultForExpression("t.x", "internal var t:ComplexParameterizedType<integer>").getType()));
+		assertTrue(isIntegerType(inferTypeResultForExpression("t.x.x",
+				"internal var t:ComplexParameterizedType<ComplexParameterizedType<integer> >").getType()));
+
+		assertTrue(
+				isAnyType(inferTypeResultForExpression("t.x", "internal var t:ComplexParameterizedType<>").getType()));
+
+		assertTrue(isAnyType(inferTypeResultForExpression("t.x", "internal var t:ComplexParameterizedType").getType()));
+
+		assertTrue(isAnyType(inferTypeResultForExpression("t.x.x",
+				"internal var t:ComplexParameterizedType<ComplexParameterizedType<> >").getType()));
+	}
 }

+ 9 - 5
test-plugins/org.yakindu.sct.model.stext.test/src/org/yakindu/sct/model/stext/test/util/AbstractTypeInferrerTest.java

@@ -84,23 +84,27 @@ public abstract class AbstractTypeInferrerTest extends AbstractSTextTest {
 	}
 
 	protected boolean isVoidType(Type type) {
-		return isType(type, "void");
+		return isType(type, ITypeSystem.VOID);
 	}
 
 	protected boolean isIntegerType(Type type) {
-		return isType(type, "integer");
+		return isType(type, ITypeSystem.INTEGER);
 	}
 
 	protected boolean isRealType(Type type) {
-		return isType(type, "real");
+		return isType(type, ITypeSystem.REAL);
 	}
 
 	protected boolean isBooleanType(Type type) {
-		return isType(type, "boolean");
+		return isType(type, ITypeSystem.BOOLEAN);
 	}
 
 	protected boolean isStringType(Type type) {
-		return isType(type, "string");
+		return isType(type, ITypeSystem.STRING);
+	}
+	
+	protected boolean isAnyType(Type type) {
+		return isType(type, ITypeSystem.ANY);
 	}
 	
 	protected void expectIssue(Type object, String message) {

+ 29 - 1
test-plugins/org.yakindu.sct.model.stext.test/src/org/yakindu/sct/model/stext/test/util/STextTestScopeProvider.java

@@ -29,6 +29,7 @@ import org.yakindu.base.types.EnumerationType;
 import org.yakindu.base.types.Enumerator;
 import org.yakindu.base.types.Property;
 import org.yakindu.base.types.Type;
+import org.yakindu.base.types.TypeParameter;
 import org.yakindu.base.types.TypeSpecifier;
 import org.yakindu.base.types.TypesFactory;
 import org.yakindu.base.types.typesystem.GenericTypeSystem;
@@ -74,7 +75,14 @@ public class STextTestScopeProvider extends STextScopeProvider {
 		for (Declaration feature : complexType.getFeatures()) {
 			descriptions.add(createEObjectDesc(feature));
 		}
-
+		
+		ComplexType cmplxParamType = createComplexParameterizedType();
+		descriptions.add(createEObjectDesc(cmplxParamType));
+		
+		for (Declaration feature : cmplxParamType.getFeatures()) {
+			descriptions.add(createEObjectDesc(feature));
+		}
+		
 		return new SimpleScope(descriptions);
 	}
 
@@ -130,5 +138,25 @@ public class STextTestScopeProvider extends STextScopeProvider {
 		enumerator.setName(name);
 		return enumerator;
 	}
+	
+	protected ComplexType createComplexParameterizedType() {
+		ComplexType complexType = TypesFactory.eINSTANCE.createComplexType();
+		complexType.setName("ComplexParameterizedType");
+		
+		TypeParameter typeParam = TypesFactory.eINSTANCE.createTypeParameter();
+		complexType.getParameter().add(typeParam);
+
+		Property featureX = TypesFactory.eINSTANCE.createProperty();
+		featureX.setName("x");
+		TypeSpecifier typeSpec = TypesFactory.eINSTANCE.createTypeSpecifier();
+		typeSpec.setType(typeParam);
+		featureX.setTypeSpecifier(typeSpec);
+		complexType.getFeatures().add(featureX);
+
+		Resource resource = new ResourceImpl(URI.createURI("types2"));
+		resource.getContents().add(complexType);
+
+		return complexType;
+	}
 
 }