Browse Source

Operation argument can be of a subtype of the parameter type (#1431) (#1455)

* Operation argument can be of a subtype of the parameter type (#1431)

* Adapt to switch in error message (expectation is named first)
Thomas Kutz 8 years ago
parent
commit
4c9b295413

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

@@ -306,8 +306,8 @@ public class ExpressionsTypeInferrer extends AbstractTypeSystemInferrer implemen
 				InferenceResult argumentType = inferTypeDispatch(argument);
 				parameterType = typeParameterInferrer.buildInferenceResult(parameterType, typeParameterMapping,
 						acceptor);
-				assertCompatible(argumentType, parameterType,
-						String.format(INCOMPATIBLE_TYPES, argumentType, parameterType));
+				assertAssignable(parameterType, argumentType,
+						String.format(INCOMPATIBLE_TYPES, parameterType, argumentType));
 			}
 		}
 		if (operation.isVariadic() && args.size() - 1 >= operation.getVarArgIndex()) {

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

@@ -735,6 +735,59 @@ public class TypeInferrerTest extends AbstractTypeInferrerTest {
 		expectIssue(inferType("boolVar = intOp()"),
 				"Assignment operator '=' may only be applied on compatible types, not on boolean and integer.");
 	}
+	
+	@Test
+	public void testOperationCall() {
+		String scope = "internal " 
+				+ "operation opInt(p:integer) : void "
+				+ "operation opReal(p:real) : void "
+				+ "operation opString(p:string) : void "
+				+ "operation opBoolean(p:boolean) : void "
+				+ "operation opSubInt(p:SubInt) : void "
+				+ "operation opSubReal(p:SubReal) : void "
+				+ "operation opSubString(p:SubString) : void "
+				+ "operation opSubBool(p:SubBool) : void "
+				+ "var vi : integer "
+				+ "var vr : real "
+				+ "var vb : boolean "
+				+ "var vs : string "
+				+ "var vsi : SubInt "
+				+ "var vsr : SubReal "
+				+ "var vsb : SubBool "
+				+ "var vss : SubString ";
+		
+		expectNoErrors("opInt(1)", scope);
+		expectNoErrors("opInt(vi)", scope);
+		expectNoErrors("opInt(vsi)", scope);
+		
+		expectNoErrors("opReal(1.1)", scope);
+		expectNoErrors("opReal(1)", scope);
+		expectNoErrors("opReal(vr)", scope);
+		expectNoErrors("opReal(vsr)", scope);
+		
+		expectNoErrors("opString(\"hello\")", scope);
+		expectNoErrors("opString(vs)", scope);
+		expectNoErrors("opString(vss)", scope);
+		
+		expectNoErrors("opBoolean(true)", scope);
+		expectNoErrors("opBoolean(vb)", scope);
+		expectNoErrors("opBoolean(vsb)", scope);
+		
+		expectErrors("opInt(1.1)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 1);
+		expectErrors("opInt(vr)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 1);
+		expectErrors("opInt(vsr)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 1);
+		
+		expectErrors("opSubInt(vi)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 1);
+		expectErrors("opSubReal(vr)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 1);
+		expectErrors("opSubBool(vb)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 1);
+		expectErrors("opSubString(vs)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 1);
+		
+		// TODO: actually one would expect these to work
+//		expectNoErrors("opSubInt(1)", scope);
+//		expectNoErrors("opSubReal(1.1)", scope);
+//		expectNoErrors("opSubBool(true)", scope);
+//		expectNoErrors("opSubString(\"hello\")", scope);
+	}
 
 	@Test
 	public void testParenthesizedExpression() {

+ 7 - 2
test-plugins/org.yakindu.sct.model.stext.test/src/org/yakindu/sct/model/stext/test/util/STextTestScopeProvider.xtend

@@ -88,6 +88,11 @@ class STextTestScopeProvider extends STextScopeProvider {
 		addToIndex(descriptions, nestedNestedTemplate)
 		addToIndex(descriptions, nestedNestedTemplate.member.head)
 		
+		addToIndex(descriptions, createPrimitiveType("SubBool", BOOLEAN))
+		addToIndex(descriptions, createPrimitiveType("SubReal", REAL))
+		addToIndex(descriptions, createPrimitiveType("SubInt", INTEGER))
+		addToIndex(descriptions, createPrimitiveType("SubString", STRING))
+		
 		return new SimpleScope(descriptions)
 	}
 	
@@ -99,7 +104,7 @@ class STextTestScopeProvider extends STextScopeProvider {
 			}
 		}
 	}
-
+	
 	def protected State createDummyModel() {
 		val stateA = createState => [
 			name = "A"
@@ -398,5 +403,5 @@ class STextTestScopeProvider extends STextScopeProvider {
 			]
 		]
 	}
-
+	
 }

+ 35 - 27
test-plugins/org.yakindu.sct.model.stext.test/src/org/yakindu/sct/model/stext/test/util/TypesTestFactory.xtend

@@ -1,11 +1,11 @@
 /**
-* Copyright (c) 2016 itemis AG - All rights Reserved
-* Unauthorized copying of this file, via any medium is strictly prohibited
-* 
-* Contributors:
-* 	Thomas Kutz - itemis AG
-*
-*/
+ * Copyright (c) 2016 itemis AG - All rights Reserved
+ * Unauthorized copying of this file, via any medium is strictly prohibited
+ * 
+ * Contributors:
+ * 	Thomas Kutz - itemis AG
+ * 
+ */
 package org.yakindu.sct.model.stext.test.util
 
 import com.google.inject.Inject
@@ -15,37 +15,38 @@ import org.yakindu.base.types.TypesFactory
 import org.yakindu.base.types.typesystem.ITypeSystem
 import org.yakindu.base.types.Enumerator
 import org.yakindu.base.types.Package
+import org.yakindu.base.types.PrimitiveType
 
 class TypesTestFactory {
-	
+
 	public static final TypesTestFactory INSTANCE = new TypesTestFactory();
-	
-	@Inject 
+
+	@Inject
 	protected ITypeSystem ts;
-	
+
 	protected TypesFactory factory = TypesFactory.eINSTANCE
-	
+
 	def Package createRootPackage(String filename) {
 		factory.createPackage => [
 			it.name = filename
 		]
 	}
-	
+
 	def createParameter(String name, String typeName) {
 		createParameter(name, toTypeSpecifier(ts.getType(typeName)));
 	}
-	
+
 	def createParameter(String name, Type type) {
 		createParameter(name, type.toTypeSpecifier);
 	}
-	
+
 	def createParameter(String name, TypeSpecifier typeSpec) {
 		factory.createParameter => [
 			it.name = name
 			it.typeSpecifier = typeSpec
 		]
 	}
-	
+
 	def createProperty(String name, String typeName) {
 		createProperty(name, typeName, false);
 	}
@@ -53,49 +54,56 @@ class TypesTestFactory {
 	def createProperty(String name, String typeName, boolean isConst) {
 		createProperty(name, ts.getType(typeName)) => [const = isConst];
 	}
-	
+
 	def createProperty(String name, Type type) {
 		createProperty(name, type.toTypeSpecifier);
 	}
-	
+
 	def createProperty(String name, TypeSpecifier typeSpec) {
 		factory.createProperty => [
 			it.name = name
 			it.typeSpecifier = typeSpec
 		]
 	}
-	
+
 	def createOperation(String name, String returnType) {
 		createOperation(name, ts.getType(returnType))
 	}
-	
+
 	def createOperation(String name, Type returnType) {
 		factory.createOperation => [
 			it.name = name
 			it.typeSpecifier = returnType.toTypeSpecifier
 		]
 	}
-	
+
 	def toTypeSpecifier(String typeName) {
 		toTypeSpecifier(ts.getType(typeName));
 	}
-	
+
 	def toTypeSpecifier(Type type) {
 		factory.createTypeSpecifier => [
 			it.type = type
 		]
 	}
-	
+
 	def createTypeParameter(String name) {
 		factory.createTypeParameter => [
 			it.name = name
 		]
 	}
-	
+
 	def Enumerator createEnumerator(String name) {
 		factory.createEnumerator => [
-			it.name = name 
+			it.name = name
 		]
 	}
-	
-}
+
+	def PrimitiveType createPrimitiveType(String name, String baseTypeName) {
+		factory.createPrimitiveType => [
+			it.name = name
+			it.baseType = ts.getType(baseTypeName) as PrimitiveType
+		]
+	}
+
+}

+ 1 - 1
test-plugins/org.yakindu.sct.model.stext.test/src/org/yakindu/sct/model/stext/test/validation/STextJavaValidatorTest.java

@@ -198,7 +198,7 @@ public class STextJavaValidatorTest extends AbstractSTextValidationTest implemen
 
 		model = super.parseExpression("myOperation2('','')", Expression.class.getSimpleName(), scope);
 		validationResult = tester.validate(model);
-		validationResult.assertErrorContains("Incompatible types string and integer.");
+		validationResult.assertErrorContains("Incompatible types integer and string.");
 
 		scope = "internal: operation myOperation(param1... : integer, param2...: integer)";
 		model = super.parseExpression(scope, InternalScope.class.getSimpleName());