Просмотр исходного кода

For variadic operation parameter, arguments need to by type-assignable to parameter type (#1431) (#1458)

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

* Adapt to switch in error message (expectation is named first)

* For variadic operation parameter, arguments need to by type-assignable to parameter type (#1431)

* Switch types in error message
Thomas Kutz 8 лет назад
Родитель
Сommit
8571ff2e24

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

@@ -307,26 +307,24 @@ public class ExpressionsTypeInferrer extends AbstractTypeSystemInferrer implemen
 				parameterType = typeParameterInferrer.buildInferenceResult(parameterType, typeParameterMapping,
 						acceptor);
 				assertAssignable(parameterType, argumentType,
-						String.format(INCOMPATIBLE_TYPES, parameterType, argumentType));
+						String.format(INCOMPATIBLE_TYPES, argumentType, parameterType));
 			}
 		}
 		if (operation.isVariadic() && args.size() - 1 >= operation.getVarArgIndex()) {
 			Parameter parameter = operation.getParameters().get(operation.getVarArgIndex());
 			List<Expression> varArgs = args.subList(operation.getVarArgIndex(), args.size() - 1);
+			InferenceResult parameterType = inferTypeDispatch(parameter);
 			for (Expression expression : varArgs) {
-				// TODO: handle op(T...)
-				assertArgumentIsCompatible(parameter, expression);
+				parameterType = typeParameterInferrer.buildInferenceResult(parameterType, typeParameterMapping,
+						acceptor);
+				InferenceResult argumentType = inferTypeDispatch(expression);
+				assertAssignable(parameterType, argumentType,
+						String.format(INCOMPATIBLE_TYPES, argumentType, parameterType));
 			}
 		}
 		return typeParameterMapping;
 	}
 
-	protected void assertArgumentIsCompatible(Parameter parameter, Expression argument) {
-		InferenceResult result1 = inferTypeDispatch(parameter);
-		InferenceResult result2 = inferTypeDispatch(argument);
-		assertCompatible(result2, result1, String.format(INCOMPATIBLE_TYPES, result2, result1));
-	}
-
 	public InferenceResult doInfer(ParenthesizedExpression e) {
 		return inferTypeDispatch(e.getExpression());
 	}

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

@@ -788,6 +788,59 @@ public class TypeInferrerTest extends AbstractTypeInferrerTest {
 //		expectNoErrors("opSubBool(true)", scope);
 //		expectNoErrors("opSubString(\"hello\")", scope);
 	}
+	
+	@Test
+	public void testOperationCallVarArgs() {
+		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("opInt(1, vi, vsi)", scope);
+		
+		expectNoErrors("opReal(1.1)", scope);
+		expectNoErrors("opReal(1)", scope);
+		expectNoErrors("opReal(vr)", scope);
+		expectNoErrors("opReal(vsr)", scope);
+		expectNoErrors("opReal(1.1, 1, vr, vsr)", scope);
+		
+		expectNoErrors("opString(\"hello\")", scope);
+		expectNoErrors("opString(vs)", scope);
+		expectNoErrors("opString(vss)", scope);
+		expectNoErrors("opString(\"hello\", vs, vss)", scope);
+		
+		expectNoErrors("opBoolean(true)", scope);
+		expectNoErrors("opBoolean(vb)", scope);
+		expectNoErrors("opBoolean(vsb)", scope);
+		expectNoErrors("opBoolean(true, vb, 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("opInt(1.1, vr, vsr)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 3);
+		
+		expectErrors("opSubInt(vi, vi)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 2);
+		expectErrors("opSubReal(vr, vr)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 2);
+		expectErrors("opSubBool(vb, vb)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 2);
+		expectErrors("opSubString(vs, vs)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE, 2);
+		
+	}
 
 	@Test
 	public void testParenthesizedExpression() {

+ 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 integer and string.");
+		validationResult.assertErrorContains("Incompatible types string and integer.");
 
 		scope = "internal: operation myOperation(param1... : integer, param2...: integer)";
 		model = super.parseExpression(scope, InternalScope.class.getSimpleName());