diff options
Diffstat (limited to 'subprojects/language/src')
-rw-r--r-- | subprojects/language/src/main/java/tools/refinery/language/typesystem/TypedModule.java | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/subprojects/language/src/main/java/tools/refinery/language/typesystem/TypedModule.java b/subprojects/language/src/main/java/tools/refinery/language/typesystem/TypedModule.java index de923e0d..6691f0ae 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/typesystem/TypedModule.java +++ b/subprojects/language/src/main/java/tools/refinery/language/typesystem/TypedModule.java | |||
@@ -11,6 +11,8 @@ import org.eclipse.emf.ecore.EObject; | |||
11 | import org.eclipse.emf.ecore.EStructuralFeature; | 11 | import org.eclipse.emf.ecore.EStructuralFeature; |
12 | import org.eclipse.xtext.validation.CheckType; | 12 | import org.eclipse.xtext.validation.CheckType; |
13 | import org.eclipse.xtext.validation.FeatureBasedDiagnostic; | 13 | import org.eclipse.xtext.validation.FeatureBasedDiagnostic; |
14 | import org.jetbrains.annotations.NotNull; | ||
15 | import org.jetbrains.annotations.Nullable; | ||
14 | import tools.refinery.language.expressions.BuiltinTermInterpreter; | 16 | import tools.refinery.language.expressions.BuiltinTermInterpreter; |
15 | import tools.refinery.language.expressions.TermInterpreter; | 17 | import tools.refinery.language.expressions.TermInterpreter; |
16 | import tools.refinery.language.model.problem.*; | 18 | import tools.refinery.language.model.problem.*; |
@@ -166,6 +168,7 @@ public class TypedModule { | |||
166 | return ExprType.NODE; | 168 | return ExprType.NODE; |
167 | } | 169 | } |
168 | 170 | ||
171 | @NotNull | ||
169 | public ExprType getExpressionType(Expr expr) { | 172 | public ExprType getExpressionType(Expr expr) { |
170 | // We can't use computeIfAbsent here, because translating referenced queries calls this method in a reentrant | 173 | // We can't use computeIfAbsent here, because translating referenced queries calls this method in a reentrant |
171 | // way, which would cause a ConcurrentModificationException with computeIfAbsent. | 174 | // way, which would cause a ConcurrentModificationException with computeIfAbsent. |
@@ -179,6 +182,7 @@ public class TypedModule { | |||
179 | return type.unwrapIfSet(); | 182 | return type.unwrapIfSet(); |
180 | } | 183 | } |
181 | 184 | ||
185 | @NotNull | ||
182 | private ExprType computeExpressionType(Expr expr) { | 186 | private ExprType computeExpressionType(Expr expr) { |
183 | return switch (expr) { | 187 | return switch (expr) { |
184 | case LogicConstant logicConstant -> computeExpressionType(logicConstant); | 188 | case LogicConstant logicConstant -> computeExpressionType(logicConstant); |
@@ -206,6 +210,7 @@ public class TypedModule { | |||
206 | }; | 210 | }; |
207 | } | 211 | } |
208 | 212 | ||
213 | @NotNull | ||
209 | private ExprType computeExpressionType(LogicConstant expr) { | 214 | private ExprType computeExpressionType(LogicConstant expr) { |
210 | return switch (expr.getLogicValue()) { | 215 | return switch (expr.getLogicValue()) { |
211 | case TRUE, FALSE -> BuiltinTermInterpreter.BOOLEAN_TYPE; | 216 | case TRUE, FALSE -> BuiltinTermInterpreter.BOOLEAN_TYPE; |
@@ -214,6 +219,7 @@ public class TypedModule { | |||
214 | }; | 219 | }; |
215 | } | 220 | } |
216 | 221 | ||
222 | @NotNull | ||
217 | private ExprType computeExpressionType(VariableOrNodeExpr expr) { | 223 | private ExprType computeExpressionType(VariableOrNodeExpr expr) { |
218 | var target = expr.getVariableOrNode(); | 224 | var target = expr.getVariableOrNode(); |
219 | if (target == null || target.eIsProxy()) { | 225 | if (target == null || target.eIsProxy()) { |
@@ -239,12 +245,14 @@ public class TypedModule { | |||
239 | }; | 245 | }; |
240 | } | 246 | } |
241 | 247 | ||
248 | @NotNull | ||
242 | private ExprType computeExpressionType(AssignmentExpr expr) { | 249 | private ExprType computeExpressionType(AssignmentExpr expr) { |
243 | // Force the left side to type check. Since the left side is a variable, it will force the right side to also | 250 | // Force the left side to type check. Since the left side is a variable, it will force the right side to also |
244 | // type check in order to infer the variable type. | 251 | // type check in order to infer the variable type. |
245 | return getExpressionType(expr.getLeft()) == ExprType.INVALID ? ExprType.INVALID : ExprType.LITERAL; | 252 | return getExpressionType(expr.getLeft()) == ExprType.INVALID ? ExprType.INVALID : ExprType.LITERAL; |
246 | } | 253 | } |
247 | 254 | ||
255 | @NotNull | ||
248 | private ExprType computeExpressionType(Atom atom) { | 256 | private ExprType computeExpressionType(Atom atom) { |
249 | var relation = atom.getRelation(); | 257 | var relation = atom.getRelation(); |
250 | if (relation == null || relation.eIsProxy()) { | 258 | if (relation == null || relation.eIsProxy()) { |
@@ -271,6 +279,7 @@ public class TypedModule { | |||
271 | return ok ? signature.resultType() : ExprType.INVALID; | 279 | return ok ? signature.resultType() : ExprType.INVALID; |
272 | } | 280 | } |
273 | 281 | ||
282 | @NotNull | ||
274 | private ExprType computeExpressionType(NegationExpr negationExpr) { | 283 | private ExprType computeExpressionType(NegationExpr negationExpr) { |
275 | var body = negationExpr.getBody(); | 284 | var body = negationExpr.getBody(); |
276 | if (body == null) { | 285 | if (body == null) { |
@@ -281,7 +290,7 @@ public class TypedModule { | |||
281 | // Negation of literals yields another (non-enumerable) literal. | 290 | // Negation of literals yields another (non-enumerable) literal. |
282 | return ExprType.LITERAL; | 291 | return ExprType.LITERAL; |
283 | } | 292 | } |
284 | if (actualType == DataExprType.INVALID) { | 293 | if (actualType == ExprType.INVALID) { |
285 | return ExprType.INVALID; | 294 | return ExprType.INVALID; |
286 | } | 295 | } |
287 | if (actualType instanceof MutableType) { | 296 | if (actualType instanceof MutableType) { |
@@ -299,6 +308,7 @@ public class TypedModule { | |||
299 | return ExprType.INVALID; | 308 | return ExprType.INVALID; |
300 | } | 309 | } |
301 | 310 | ||
311 | @NotNull | ||
302 | private ExprType computeExpressionType(ArithmeticUnaryExpr expr) { | 312 | private ExprType computeExpressionType(ArithmeticUnaryExpr expr) { |
303 | var op = expr.getOp(); | 313 | var op = expr.getOp(); |
304 | var body = expr.getBody(); | 314 | var body = expr.getBody(); |
@@ -306,7 +316,7 @@ public class TypedModule { | |||
306 | return ExprType.INVALID; | 316 | return ExprType.INVALID; |
307 | } | 317 | } |
308 | var actualType = getExpressionType(body); | 318 | var actualType = getExpressionType(body); |
309 | if (actualType == DataExprType.INVALID) { | 319 | if (actualType == ExprType.INVALID) { |
310 | return ExprType.INVALID; | 320 | return ExprType.INVALID; |
311 | } | 321 | } |
312 | if (actualType instanceof MutableType) { | 322 | if (actualType instanceof MutableType) { |
@@ -324,14 +334,16 @@ public class TypedModule { | |||
324 | return ExprType.INVALID; | 334 | return ExprType.INVALID; |
325 | } | 335 | } |
326 | 336 | ||
337 | @NotNull | ||
327 | private ExprType computeExpressionType(CountExpr countExpr) { | 338 | private ExprType computeExpressionType(CountExpr countExpr) { |
328 | return coerceIntoLiteral(countExpr.getBody()) ? BuiltinTermInterpreter.INT_TYPE : ExprType.INVALID; | 339 | return coerceIntoLiteral(countExpr.getBody()) ? BuiltinTermInterpreter.INT_TYPE : ExprType.INVALID; |
329 | } | 340 | } |
330 | 341 | ||
342 | @NotNull | ||
331 | private ExprType computeExpressionType(AggregationExpr expr) { | 343 | private ExprType computeExpressionType(AggregationExpr expr) { |
332 | var aggregator = expr.getAggregator(); | 344 | var aggregator = expr.getAggregator(); |
333 | if (aggregator == null || aggregator.eIsProxy()) { | 345 | if (aggregator == null || aggregator.eIsProxy()) { |
334 | return null; | 346 | return ExprType.INVALID; |
335 | } | 347 | } |
336 | // Avoid short-circuiting to let us type check both the value and the condition. | 348 | // Avoid short-circuiting to let us type check both the value and the condition. |
337 | boolean ok = coerceIntoLiteral(expr.getCondition()); | 349 | boolean ok = coerceIntoLiteral(expr.getCondition()); |
@@ -356,6 +368,7 @@ public class TypedModule { | |||
356 | return ExprType.INVALID; | 368 | return ExprType.INVALID; |
357 | } | 369 | } |
358 | 370 | ||
371 | @NotNull | ||
359 | private ExprType computeExpressionType(ComparisonExpr expr) { | 372 | private ExprType computeExpressionType(ComparisonExpr expr) { |
360 | var left = expr.getLeft(); | 373 | var left = expr.getLeft(); |
361 | var right = expr.getRight(); | 374 | var right = expr.getRight(); |
@@ -378,11 +391,13 @@ public class TypedModule { | |||
378 | return BuiltinTermInterpreter.BOOLEAN_TYPE; | 391 | return BuiltinTermInterpreter.BOOLEAN_TYPE; |
379 | } | 392 | } |
380 | 393 | ||
394 | @NotNull | ||
381 | private ExprType computeExpressionType(LatticeBinaryExpr expr) { | 395 | private ExprType computeExpressionType(LatticeBinaryExpr expr) { |
382 | // Lattice operations are always supported for data types. | 396 | // Lattice operations are always supported for data types. |
383 | return getCommonDataType(expr); | 397 | return getCommonDataType(expr); |
384 | } | 398 | } |
385 | 399 | ||
400 | @NotNull | ||
386 | private ExprType computeExpressionType(RangeExpr expr) { | 401 | private ExprType computeExpressionType(RangeExpr expr) { |
387 | var left = expr.getLeft(); | 402 | var left = expr.getLeft(); |
388 | var right = expr.getRight(); | 403 | var right = expr.getRight(); |
@@ -405,6 +420,7 @@ public class TypedModule { | |||
405 | return commonType; | 420 | return commonType; |
406 | } | 421 | } |
407 | 422 | ||
423 | @NotNull | ||
408 | private ExprType computeExpressionType(ArithmeticBinaryExpr expr) { | 424 | private ExprType computeExpressionType(ArithmeticBinaryExpr expr) { |
409 | var op = expr.getOp(); | 425 | var op = expr.getOp(); |
410 | var left = expr.getLeft(); | 426 | var left = expr.getLeft(); |
@@ -415,6 +431,24 @@ public class TypedModule { | |||
415 | // Avoid short-circuiting to let us type check both arguments. | 431 | // Avoid short-circuiting to let us type check both arguments. |
416 | var leftType = getExpressionType(left); | 432 | var leftType = getExpressionType(left); |
417 | var rightType = getExpressionType(right); | 433 | var rightType = getExpressionType(right); |
434 | var result = computeBinaryExpressionType(left, leftType, right, rightType, op); | ||
435 | if (result != null) { | ||
436 | return result; | ||
437 | } | ||
438 | var messageBuilder = new StringBuilder("Unsupported operator for "); | ||
439 | if (leftType.equals(rightType)) { | ||
440 | messageBuilder.append("data type ").append(leftType); | ||
441 | } else { | ||
442 | messageBuilder.append("data types ").append(leftType).append(" and ").append(rightType); | ||
443 | } | ||
444 | messageBuilder.append("."); | ||
445 | error(messageBuilder.toString(), expr, null, 0, ProblemValidator.TYPE_ERROR); | ||
446 | return ExprType.INVALID; | ||
447 | } | ||
448 | |||
449 | @Nullable | ||
450 | private ExprType computeBinaryExpressionType(Expr left, ExprType leftType, Expr right, ExprType rightType, | ||
451 | BinaryOp op) { | ||
418 | if (leftType == ExprType.INVALID || rightType == ExprType.INVALID) { | 452 | if (leftType == ExprType.INVALID || rightType == ExprType.INVALID) { |
419 | return ExprType.INVALID; | 453 | return ExprType.INVALID; |
420 | } | 454 | } |
@@ -442,22 +476,15 @@ public class TypedModule { | |||
442 | return result.get(); | 476 | return result.get(); |
443 | } | 477 | } |
444 | } | 478 | } |
445 | var messageBuilder = new StringBuilder("Unsupported operator for "); | 479 | return null; |
446 | if (leftType.equals(rightType)) { | ||
447 | messageBuilder.append("data type ").append(leftType); | ||
448 | } else { | ||
449 | messageBuilder.append("data types ").append(leftType).append(" and ").append(rightType); | ||
450 | } | ||
451 | messageBuilder.append("."); | ||
452 | error(messageBuilder.toString(), expr, null, 0, ProblemValidator.TYPE_ERROR); | ||
453 | return ExprType.INVALID; | ||
454 | } | 480 | } |
455 | 481 | ||
482 | @NotNull | ||
456 | private ExprType computeExpressionType(CastExpr expr) { | 483 | private ExprType computeExpressionType(CastExpr expr) { |
457 | var body = expr.getBody(); | 484 | var body = expr.getBody(); |
458 | var targetRelation = expr.getTargetType(); | 485 | var targetRelation = expr.getTargetType(); |
459 | if (body == null || !(targetRelation instanceof DatatypeDeclaration targetDeclaration)) { | 486 | if (body == null || !(targetRelation instanceof DatatypeDeclaration targetDeclaration)) { |
460 | return null; | 487 | return ExprType.INVALID; |
461 | } | 488 | } |
462 | var actualType = getExpressionType(body); | 489 | var actualType = getExpressionType(body); |
463 | if (actualType == ExprType.INVALID) { | 490 | if (actualType == ExprType.INVALID) { |