Skip to content

Commit 0fe6e6c

Browse files
committed
Merge branch 'mr/pmderodat/3-pred-type-check' into 'master'
Predicate: type check nodes that come from logic variables See merge request eng/libadalang/langkit!1209
2 parents 77dd3ca + 37e9304 commit 0fe6e6c

File tree

6 files changed

+142
-7
lines changed

6 files changed

+142
-7
lines changed

langkit/templates/properties/helpers.mako

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,12 @@
207207
type_name = f"{pred.id}_Predicate"
208208
package_name = f"{pred.id}_Pred"
209209
formal_node_types = prop.get_concrete_node_types(pred)
210+
enumerated_arg_types = list(enumerate(formal_node_types[1:], 1))
210211
arity = len(formal_node_types)
211212
has_refcounted_args = any(
212213
pa.type.is_refcounted for pa in pred.partial_args
213214
)
215+
has_multiple_concrete_nodes = len(T.root_node.concrete_subclasses) > 1
214216
%>
215217
216218
<%def name="call_profile()">
@@ -313,11 +315,11 @@
313315
Entity : ${T.entity.name} := Entities (1);
314316
% endif
315317
<% node0_type = formal_node_types[0] %>
316-
Node : constant ${node0_type.name} := Entity.Node;
318+
Node : ${node0_type.name};
317319
begin
318320
## Here, we'll raise a property error, but only for dispatching
319-
## properties. For non dispatching properties we'll allow the user to
320-
## handle null however he wants.
321+
## properties. For non dispatching properties we'll allow the user
322+
## property to handle null however it wants.
321323
% if prop.dispatching and not ctx.no_property_checks:
322324
if Node_0.Node = null then
323325
Raise_Property_Exception
@@ -327,15 +329,44 @@
327329
end if;
328330
% endif
329331
332+
## Type check nodes that come from logic vars to avoid Assertion_Error or
333+
## Assertion_Error in case of mismatch.
334+
% if not ctx.emitter.no_property_checks:
335+
<%
336+
typed_nodes = (
337+
[("Entity.Node", prop.struct)]
338+
+ [
339+
(f"Entities ({i + 1}).Node", t.element_type)
340+
for i, t in enumerated_arg_types
341+
]
342+
)
343+
%>
344+
% for node_expr, node_type in typed_nodes:
345+
% if has_multiple_concrete_nodes and not node_type.is_root_node:
346+
if ${node_expr} /= null
347+
and then ${node_expr}.Kind
348+
not in ${node_type.ada_kind_range_name}
349+
then
350+
Raise_Property_Exception
351+
(Node, Property_Error'Identity, "mismatching node type");
352+
end if;
353+
% endif
354+
% endfor
355+
% endif
356+
357+
Node := Entity.Node;
358+
330359
## Pass the "prefix" node (the one that owns the property to call) using
331360
## the conventional bare node/entity_info arguments. Pass the other node
332361
## arguments as entities directly.
333362
<%
334363
args = ['Node'] + [
335364
f"(Node => Entities ({i + 1}).Node,"
336365
f" Info => Entities ({i + 1}).Info)"
337-
for i, formal_type in enumerate(formal_node_types[1:], 1)
338-
] + [f"{pa.name} => Self.Field_{pa.index}" for pa in pred.partial_args]
366+
for i, formal_type in enumerated_arg_types
367+
] + [
368+
f"{pa.name} => Self.Field_{pa.index}" for pa in pred.partial_args
369+
]
339370
if prop.uses_entity_info:
340371
args.append(f"{prop.entity_info_name} => Entity.Info")
341372
args_fmt = '({})'.format(', '.join(args)) if args else ''

testsuite/tests/properties/conv_prop_mistype/expected_concrete_syntax.lkt renamed to testsuite/tests/properties/logic_var_type_mismatch/expected_concrete_syntax.lkt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,26 @@ class Examples: FooNode {
6060
fun fail_nprop_varargs(): Bool = (
6161
%propagate(node.pe.lvar, PlusExample.ncomb_prop, [node.pe.lvar, node.re.lvar]) and node.domains()
6262
).solve()
63+
64+
@exported
65+
fun ok_pred(): Bool = (
66+
%predicate(PlusExample.pred_prop, node.pe.lvar, node.re.lvar, node.pe.lvar) and node.domains()
67+
).solve()
68+
69+
@exported
70+
fun fail_pred_1(): Bool = (
71+
%predicate(PlusExample.pred_prop, node.re.lvar, node.re.lvar, node.pe.lvar) and node.domains()
72+
).solve()
73+
74+
@exported
75+
fun fail_pred_2(): Bool = (
76+
%predicate(PlusExample.pred_prop, node.pe.lvar, node.pe.lvar, node.pe.lvar) and node.domains()
77+
).solve()
78+
79+
@exported
80+
fun fail_pred_3(): Bool = (
81+
%predicate(PlusExample.pred_prop, node.pe.lvar, node.re.lvar, node.re.lvar) and node.domains()
82+
).solve()
6383
}
6484

6585
class PlusExample: FooNode {
@@ -70,6 +90,9 @@ class PlusExample: FooNode {
7090

7191
fun ncomb_prop(pe_list: Array[Entity[PlusExample]]): Entity[PlusExample] =
7292
pe_list?[0]
93+
94+
fun pred_prop(@ignored re: Entity[RegularExample], @ignored pe: Entity[PlusExample]): Bool =
95+
true
7396
}
7497

7598
class RegularExample: FooNode {

testsuite/tests/properties/conv_prop_mistype/main.adb renamed to testsuite/tests/properties/logic_var_type_mismatch/main.adb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ begin
5050
Check ("p_fail_nprop_multi_3", P_Fail_Nprop_Multi_3'Access);
5151
Check ("p_ok_nprop_varargs", P_Ok_Nprop_Varargs'Access);
5252
Check ("p_fail_nprop_varargs", P_Fail_Nprop_Varargs'Access);
53+
Check ("p_ok_pred", P_Ok_Pred'Access);
54+
Check ("p_fail_pred_1", P_Fail_Pred_1'Access);
55+
Check ("p_fail_pred_2", P_Fail_Pred_2'Access);
56+
Check ("p_fail_pred_3", P_Fail_Pred_3'Access);
5357

5458
Put_Line ("main.adb: Done.");
5559
end Main;

testsuite/tests/properties/conv_prop_mistype/test.out renamed to testsuite/tests/properties/logic_var_type_mismatch/test.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,17 @@ Result: TRUE
2323
Calling Examples.p_fail_nprop_varargs...
2424
Got a Property_Error: main.txt:1:1-1:8: mismatching node type for comb_prop
2525

26+
Calling Examples.p_ok_pred...
27+
Result: TRUE
28+
29+
Calling Examples.p_fail_pred_1...
30+
Got a Property_Error: mismatching node type
31+
32+
Calling Examples.p_fail_pred_2...
33+
Got a Property_Error: mismatching node type
34+
35+
Calling Examples.p_fail_pred_3...
36+
Got a Property_Error: mismatching node type
37+
2638
main.adb: Done.
2739
Done

testsuite/tests/properties/conv_prop_mistype/test.py renamed to testsuite/tests/properties/logic_var_type_mismatch/test.py

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
Bind,
99
Entity,
1010
NPropagate,
11+
Predicate,
1112
Self,
1213
ignore,
1314
langkit_property,
@@ -33,7 +34,7 @@ def domains():
3334
return Self.re.lvar.domain([Self.re]) & Self.pe.lvar.domain([Self.pe])
3435

3536
# PropertyError expected when PlusExample.conv_prop is called on a
36-
# RegularExample.
37+
# RegularExample node.
3738

3839
@langkit_property(public=True)
3940
def fail_bind_conv_prop():
@@ -65,7 +66,7 @@ def ok_nprop_multi():
6566
).solve
6667

6768
# PropertyError expected when PlusExample.comb_prop is called on a
68-
# RegularExample.
69+
# RegularExample node.
6970

7071
@langkit_property(public=True)
7172
def fail_nprop_multi_1():
@@ -140,6 +141,65 @@ def fail_nprop_varargs():
140141
& Self.domains
141142
).solve
142143

144+
# Successful example of a Predicate (as a sanity check)
145+
146+
@langkit_property(public=True)
147+
def ok_pred():
148+
return (
149+
Predicate(
150+
PlusExample.pred_prop,
151+
Self.pe.lvar,
152+
Self.re.lvar,
153+
Self.pe.lvar,
154+
)
155+
& Self.domains
156+
).solve
157+
158+
# PropertyError expected when PlusExample.pred_prop is called on a
159+
# RegularExample node.
160+
161+
@langkit_property(public=True)
162+
def fail_pred_1():
163+
return (
164+
Predicate(
165+
PlusExample.pred_prop,
166+
Self.re.lvar,
167+
Self.re.lvar,
168+
Self.pe.lvar,
169+
)
170+
& Self.domains
171+
).solve
172+
173+
# PropertyError expected when PlusExample.pred_prop is called with a
174+
# PlusExample for its "re" argument.
175+
176+
@langkit_property(public=True)
177+
def fail_pred_2():
178+
return (
179+
Predicate(
180+
PlusExample.pred_prop,
181+
Self.pe.lvar,
182+
Self.pe.lvar,
183+
Self.pe.lvar,
184+
)
185+
& Self.domains
186+
).solve
187+
188+
# PropertyError expected when PlusExample.pred_prop is called with a
189+
# RegularExample for its "pe" argument.
190+
191+
@langkit_property(public=True)
192+
def fail_pred_3():
193+
return (
194+
Predicate(
195+
PlusExample.pred_prop,
196+
Self.pe.lvar,
197+
Self.re.lvar,
198+
Self.re.lvar,
199+
)
200+
& Self.domains
201+
).solve
202+
143203

144204
class RegularExample(FooNode):
145205
pass
@@ -160,6 +220,11 @@ def comb_prop(re=T.RegularExample.entity, pe=T.PlusExample.entity):
160220
def ncomb_prop(pe_list=T.PlusExample.entity.array):
161221
return pe_list.at(0)
162222

223+
@langkit_property()
224+
def pred_prop(re=T.RegularExample.entity, pe=T.PlusExample.entity):
225+
ignore(re, pe)
226+
return True
227+
163228

164229
build_and_run(
165230
lkt_file="expected_concrete_syntax.lkt",

0 commit comments

Comments
 (0)