# HG changeset patch
# User Alain Leufroy <alain.leufroy@logilab.fr>
# Date 1398347179 -7200
#      Thu Apr 24 15:46:19 2014 +0200
# Node ID dbb9798ea5ad2a56d5aca5b77afdef62293d6e8b
# Parent  a9ef868f04446ffecaac831d2c5f52a879ab651e
[stcheck] fix visit_constant checker: a etype inside a CAST is a good thing

Actually, if you put a CAST after a relation (!= ``is`` or ``is_instance_of``),
the checker raises an error saying that the etype (inside the CAST) must be
after a ``is`` or ``is_instance_of`` relation. In fact the CAST case was tested too late.

This allow to use CAST outside the selection section, so:
Closes #79232

diff --git a/stcheck.py b/stcheck.py
--- a/stcheck.py
+++ b/stcheck.py
@@ -457,18 +457,18 @@
         pass
 
     def visit_constant(self, constant, state):
-        #assert len(constant.children)==0
-        if constant.type == 'etype':
-            if constant.value not in self.schema:
-                state.error('unknown entity type %s' % constant.value)
-            rel = constant.relation()
-            if rel is not None:
-                if rel.r_type not in ('is', 'is_instance_of'):
-                    msg ='using an entity type in only allowed with "is" relation'
-                    state.error(msg)
-            elif not (isinstance(constant.parent, Function) and
-                      constant.parent.name == 'CAST'):
-                state.error('Entity types can only be used inside a CAST()')
+        if constant.type != 'etype':
+            return
+        if constant.value not in self.schema:
+            state.error('unknown entity type %s' % constant.value)
+        if (isinstance(constant.parent, Function) and
+            constant.parent.name == 'CAST'):
+            return
+        rel = constant.relation()
+        if rel is not None and rel.r_type in ('is', 'is_instance_of'):
+            return
+        state.error('Entity types can only be used inside a CAST() '
+                    'or with "is" relation')
 
     def leave_constant(self, node, state):
         pass
diff --git a/test/unittest_analyze.py b/test/unittest_analyze.py
--- a/test/unittest_analyze.py
+++ b/test/unittest_analyze.py
@@ -548,5 +548,22 @@
         self.assertEqual(sols, [{'U': 'Person'}])
 
 
+    def test_selection_with_cast(self):
+        node = self.helper.parse('Any X WHERE X name CAST(String, E), Y eid E, X owned_by Y')
+        self.helper.compute_solutions(node, debug=DEBUG)
+        sols = sorted(node.children[0].solutions)
+        self.assertEqual(sols, [{'E': 'Int', 'X': 'Company', 'Y': 'Person'},
+                                {'E': 'Int', 'X': 'Person', 'Y': 'Person'},
+                                {'E': 'Int', 'X': 'Student', 'Y': 'Person'}])
+
+    def test_set_with_cast(self):
+        node = self.helper.parse('SET X name CAST(String, E), X work_for Y WHERE Y eid E')
+        self.helper.compute_solutions(node, debug=DEBUG)
+        sols = sorted(node.solutions)
+        self.assertEqual(sols, [{'X': 'Person', 'Y': 'Company', 'E': 'Int'},
+                                {'X': 'Student', 'Y': 'Company', 'E': 'Int'}])
+
+
+
 if __name__ == '__main__':
     unittest_main()
diff --git a/test/unittest_stcheck.py b/test/unittest_stcheck.py
--- a/test/unittest_stcheck.py
+++ b/test/unittest_stcheck.py
@@ -80,11 +80,10 @@
     # variable with only ?1 cardinality
     'DISTINCT Any P ORDERBY PN WHERE P work_for X, P name PN',
     'DISTINCT Any P ORDERBY XN WHERE P work_for X, X name XN',
-
     'Any X WHERE X eid > 0, X eid < 42',
     'Any X WHERE X eid 1, X eid < 42',
-
-
+    'Any X WHERE X number CAST(Int, Y), X name Y',
+    'SET X number CAST(Int, Y) WHERE X name Y',
     )
 
 class CheckClassTest(TestCase):