From 177b80066ca9f2aecfb0506f227f4e416ecfcca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Th=C3=A9venoux?= Date: Wed, 3 Nov 2021 13:38:53 +0000 Subject: [PATCH] Lkt: emit an error if PropertyError is called without raise Ensure that PropertyError is called through the raise keyword. TN: U928-029 --- contrib/lkt/language/parser.py | 28 +++++ .../lkt_semantic/property_error/test.lkt | 15 ++- .../lkt_semantic/property_error/test.out | 116 +++++++++++++----- 3 files changed, 122 insertions(+), 37 deletions(-) diff --git a/contrib/lkt/language/parser.py b/contrib/lkt/language/parser.py index 90a29baa6..be391358d 100644 --- a/contrib/lkt/language/parser.py +++ b/contrib/lkt/language/parser.py @@ -459,6 +459,17 @@ def check_semantic_impl(): has_error=results.any(lambda r: r.has_error) ) + @langkit_property(return_type=T.LKNode.entity) + def first_no_paren_parent(): + """ + Return the first parent that is not a ``ParenExpr``. + """ + return If( + Entity.parent.is_a(ParenExpr), + Entity.parent.first_no_paren_parent(), + Entity.parent + ) + class LangkitRoot(LKNode): """ @@ -2571,6 +2582,23 @@ def check_correctness_pre(): ) ) ) + # In case of PropertyError, check for RaiseExpr + ._or( + If( + And( + rd.result_ref == Entity.property_error_type, + Not(Entity.first_no_paren_parent.is_a(T.RaiseExpr)) + ), + + Self.error( + S("cannot call ") + .concat(Entity.property_error_type.full_name) + .concat(S(" outside of a raise expression")) + ).singleton, + + No(T.SemanticResult.array) + ) + ) ) @langkit_property(return_type=T.InferInstantiation) diff --git a/testsuite/tests/contrib/lkt_semantic/property_error/test.lkt b/testsuite/tests/contrib/lkt_semantic/property_error/test.lkt index cf34c3c30..d6c36dbbd 100644 --- a/testsuite/tests/contrib/lkt_semantic/property_error/test.lkt +++ b/testsuite/tests/contrib/lkt_semantic/property_error/test.lkt @@ -1,11 +1,18 @@ fun prop1(): Bool = raise PropertyError("error") fun prop2(): Bool = (raise PropertyError("error")) +fun prop3(): Bool = raise (PropertyError("error")) +fun prop4(): Bool = raise (((PropertyError("error")))) + +# TODO: prop5 and prop6 should be rejected (we don't want any PropertyError +# value living outside of the exception system). +# @invalid fun prop5(): PropertyError = raise PropertyError() +# @invalid fun prop6(): Bool = raise prop5() # Invalid because of missing raise keyword -@invalid val prop3: Bool = PropertyError("error") -@invalid val prop4: Bool = (PropertyError("error")) +@invalid val prop7: Bool = PropertyError("error") +@invalid val prop8: Bool = (PropertyError("error")) -fun prop5(): Bool = { +fun prop9(): Bool = { val n: Int = 1; raise PropertyError("Explicit error") @@ -13,4 +20,4 @@ fun prop5(): Bool = { # Invalid because only PropertyError can be raised val i: Int = 1 -@invalid fun prop6(): Bool = raise i +@invalid fun prop10(): Bool = raise i diff --git a/testsuite/tests/contrib/lkt_semantic/property_error/test.out b/testsuite/tests/contrib/lkt_semantic/property_error/test.out index 9cf7ba7b5..b7f1020ef 100644 --- a/testsuite/tests/contrib/lkt_semantic/property_error/test.out +++ b/testsuite/tests/contrib/lkt_semantic/property_error/test.out @@ -33,79 +33,129 @@ Expr Expr has type -Id +Id references -Id +Id references -Expr +Expr has type -test.lkt:5:28: error: Mismatched types: expected `Bool`, got `PropertyError` -5 | @invalid val prop3: Bool = PropertyError("error") - | ^^^^^^^^^^^^^^^^^^^^^^ +Expr + has type + +Expr + has type + +Expr + has type + +Id + references + +Id + references + +Expr + has type + +Expr + has type + +Expr + has type -Id +Expr + has type + +Expr + has type + +Expr + has type + +Id references -Id +test.lkt:12:28: error: cannot call PropertyError outside of a raise expression +12 | @invalid val prop7: Bool = PropertyError("error") + | ^^^^^^^^^^^^^^^^^^^^^^ + +Id + references + +Expr + has type + +test.lkt:12:28: error: Mismatched types: expected `Bool`, got `PropertyError` +12 | @invalid val prop7: Bool = PropertyError("error") + | ^^^^^^^^^^^^^^^^^^^^^^ + +Id + references + +test.lkt:13:29: error: cannot call PropertyError outside of a raise expression +13 | @invalid val prop8: Bool = (PropertyError("error")) + | ^^^^^^^^^^^^^^^^^^^^^^ + +Id references -Expr +Expr has type -test.lkt:6:29: error: Mismatched types: expected `Bool`, got `PropertyError` -6 | @invalid val prop4: Bool = (PropertyError("error")) - | ^^^^^^^^^^^^^^^^^^^^^^ +test.lkt:13:29: error: Mismatched types: expected `Bool`, got `PropertyError` +13 | @invalid val prop8: Bool = (PropertyError("error")) + | ^^^^^^^^^^^^^^^^^^^^^^ -test.lkt:6:28: error: Mismatched types: expected `Bool`, got `PropertyError` -6 | @invalid val prop4: Bool = (PropertyError("error")) - | ^^^^^^^^^^^^^^^^^^^^^^^^ +test.lkt:13:28: error: Mismatched types: expected `Bool`, got `PropertyError` +13 | @invalid val prop8: Bool = (PropertyError("error")) + | ^^^^^^^^^^^^^^^^^^^^^^^^ -Id +Id references -Id +Id references -Expr +Expr has type -Id +Id references -Expr +Expr has type -Expr +Expr has type -Expr +Expr has type -Expr +Expr has type -Id +Id references -Expr +Expr has type -Id +Id references -test.lkt:16:36: error: raised expression needs to be of type `PropertyError`, got `Int` -16 | @invalid fun prop6(): Bool = raise i - | ^ +test.lkt:23:37: error: raised expression needs to be of type `PropertyError`, got `Int` +23 | @invalid fun prop10(): Bool = raise i + | ^ -Id - references +Id + references -Expr +Expr has type -Expr +Expr has type