Skip to content

Commit e8a2bf9

Browse files
authored
Clean infer_type function (pyccel#1837)
The function `infer_type` is critical to the `SemanticParser` but it has several issues which are fixed in this PR. Firstly the dictionary that is returned is modified to ensure that all the documented fields are defined. Fixes pyccel#1842 . This removes the need for calls to `dict.get` elsewhere in the code. Secondly the `is_target` property is removed. This property is either set to False or is incorrectly set. It is not used for calculations elsewhere. A test is added for pyccel#1842. Further the tuple tests are updated so that all objects that are supposed to be homogeneous are indexed by a variable (this is not possible for inhomogeneous objects).
1 parent c5b7e3e commit e8a2bf9

File tree

6 files changed

+78
-70
lines changed

6 files changed

+78
-70
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ All notable changes to this project will be documented in this file.
3434
- #1218 : Fix bug when assigning an array to a slice in Fortran.
3535
- #1830 : Fix missing allocation when returning an annotated array expression.
3636
- #1821 : Ensure an error is raised when creating an ambiguous interface.
37+
- #1842 : Fix homogeneous tuples incorrectly identified as inhomogeneous.
3738

3839
### Changed
3940
- #1720 : functions with the `@inline` decorator are no longer exposed to Python in the shared library.
@@ -53,6 +54,7 @@ All notable changes to this project will be documented in this file.
5354
- \[INTERNALS\] Stop storing `FunctionDef`, `ClassDef`, and `Import` objects inside `CodeBlock`s.
5455
- \[INTERNALS\] Remove the `order` argument from the `pyccel.ast.core.Allocate` constructor.
5556
- \[INTERNALS\] Remove `rank` and `order` arguments from `pyccel.ast.variable.Variable` constructor.
57+
- \[INTERNALS\] Ensure `SemanticParser.infer_type` returns all documented information.
5658

5759
### Deprecated
5860

pyccel/ast/builtins.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ def __init__(self, *args):
505505
orders = set(a.order for a in args)
506506
if len(ranks) == 1:
507507
rank = next(iter(ranks))
508-
shapes = tuple(set(a.shape[i] for a in args if not (isinstance(a.shape[i], PyccelArrayShapeElement) or \
508+
shapes = tuple(set(a.shape[i] for a in args if not (a.shape[i] is None or isinstance(a.shape[i], PyccelArrayShapeElement) or \
509509
a.shape[i].get_attribute_nodes(PyccelArrayShapeElement))) \
510510
for i in range(rank))
511511
else:

pyccel/ast/literals.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ class LiteralString(Literal):
332332
__slots__ = ('_string',)
333333
_class_type = StringType()
334334
_static_type = StringType()
335+
_shape = (None,)
335336

336337
def __init__(self, arg):
337338
super().__init__()

pyccel/parser/semantic.py

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -669,9 +669,8 @@ def _infer_type(self, expr):
669669
inferred about the expression `expr`. This includes information about:
670670
- `class_type`
671671
- `shape`
672-
- `memory_handling`
673672
- `cls_base`
674-
- `is_target`
673+
- `memory_handling`
675674
676675
Parameters
677676
----------
@@ -685,28 +684,19 @@ def _infer_type(self, expr):
685684
Dictionary containing all the type information which was inferred.
686685
"""
687686
d_var = {
688-
'shape' : expr.shape,
689687
'class_type' : expr.class_type,
688+
'shape' : expr.shape,
689+
'cls_base' : self.scope.find(str(expr.class_type), 'classes') or get_cls_base(expr.class_type),
690+
'memory_handling' : 'heap' if expr.rank > 0 else 'stack'
690691
}
691692

692693
if isinstance(expr, Variable):
693694
d_var['memory_handling'] = expr.memory_handling
694-
d_var['class_type' ] = expr.class_type
695-
d_var['cls_base' ] = expr.cls_base or self.scope.find(str(expr.dtype), 'classes')
696-
d_var['is_target' ] = expr.is_target
697-
return d_var
698-
699-
elif isinstance(expr, LiteralString):
700-
d_var['memory_handling'] = 'stack'
701-
return d_var
702-
703-
elif isinstance(expr, PythonTuple):
704-
d_var['cls_base' ] = TupleClass
705-
d_var['memory_handling'] = 'heap'
695+
if expr.cls_base:
696+
d_var['cls_base' ] = expr.cls_base
706697
return d_var
707698

708699
elif isinstance(expr, Concatenate):
709-
d_var['cls_base' ] = TupleClass
710700
if any(getattr(a, 'on_heap', False) for a in expr.args):
711701
d_var['memory_handling'] = 'heap'
712702
else:
@@ -715,24 +705,16 @@ def _infer_type(self, expr):
715705

716706
elif isinstance(expr, Duplicate):
717707
d = self._infer_type(expr.val)
718-
d_var['cls_base' ] = TupleClass
719708
if d.get('on_stack', False) and isinstance(expr.length, LiteralInteger):
720709
d_var['memory_handling'] = 'stack'
721710
else:
722711
d_var['memory_handling'] = 'heap'
723712
return d_var
724713

725-
elif isinstance(expr, NumpyNewArray):
726-
d_var['cls_base' ] = NumpyArrayClass
727-
d_var['memory_handling'] = 'heap' if expr.rank > 0 else 'stack'
728-
return d_var
729-
730714
elif isinstance(expr, NumpyTranspose):
731715

732716
var = expr.internal_var
733717

734-
d_var['cls_base' ] = var.cls_base
735-
d_var['is_target' ] = var.is_target
736718
d_var['memory_handling'] = 'alias' if isinstance(var, Variable) else 'heap'
737719
return d_var
738720

@@ -2992,7 +2974,6 @@ def _visit_FunctionCall(self, expr):
29922974
d_var = {'class_type' : dtype,
29932975
'memory_handling':'stack',
29942976
'shape' : None,
2995-
'is_target' : False,
29962977
'cls_base' : cls_def,
29972978
}
29982979
new_expression = []
@@ -3207,18 +3188,16 @@ def _visit_Assign(self, expr):
32073188
if name.startswith('Pyccel'):
32083189
name = name[6:]
32093190
d['cls_base'] = self.scope.find(name, 'classes')
3210-
#TODO: Avoid writing the default variables here
3211-
if d_var.get('is_target', False) or d_var.get('memory_handling', False) == 'alias':
3191+
if d_var['memory_handling'] == 'alias':
32123192
d['memory_handling'] = 'alias'
32133193
else:
3214-
d['memory_handling'] = d_var.get('memory_handling', False) or 'heap'
3194+
d['memory_handling'] = d_var['memory_handling'] or 'heap'
32153195

32163196
# TODO if we want to use pointers then we set target to true
32173197
# in the ConsturcterCall
32183198

32193199
if isinstance(rhs, Variable) and rhs.is_target:
32203200
# case of rhs is a target variable the lhs must be a pointer
3221-
d['is_target' ] = False
32223201
d['memory_handling'] = 'alias'
32233202

32243203
lhs = expr.lhs

tests/epyccel/modules/tuples.py

Lines changed: 65 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@
22
from pyccel.decorators import pure
33

44
__all__ = [
5-
'homogenous_tuple_int',
6-
'homogenous_tuple_bool',
7-
'homogenous_tuple_float',
8-
'homogenous_tuple_string',
9-
'homogenous_tuple_math',
5+
'homogeneous_tuple_int',
6+
'homogeneous_tuple_bool',
7+
'homogeneous_tuple_float',
8+
'homogeneous_tuple_string',
9+
'homogeneous_tuple_math',
10+
'homogeneous_tuple_containing_var',
1011
'homogeneous_tuple_of_arrays',
11-
'inhomogenous_tuple_1',
12-
'inhomogenous_tuple_2',
13-
'inhomogenous_tuple_3',
14-
'inhomogenous_tuple_2_levels_1',
15-
'inhomogenous_tuple_2_levels_2',
12+
'inhomogeneous_tuple_1',
13+
'inhomogeneous_tuple_2',
14+
'inhomogeneous_tuple_3',
15+
'inhomogeneous_tuple_2_levels_1',
16+
'inhomogeneous_tuple_2_levels_2',
1617
'homogeneous_tuple_2_levels',
1718
'tuple_unpacking_1',
1819
'tuple_unpacking_2',
@@ -76,45 +77,56 @@
7677
'tuple_different_ranks',
7778
]
7879

79-
def homogenous_tuple_int():
80+
def homogeneous_tuple_int():
8081
ai = (1,4,5)
81-
return ai[0], ai[1], ai[2]
82+
i = 1
83+
return ai[0], ai[i], ai[2]
8284

83-
def homogenous_tuple_bool():
85+
def homogeneous_tuple_bool():
8486
ai = (False, True)
85-
return ai[0], ai[1]
87+
i = 1
88+
return ai[0], ai[i]
8689

87-
def homogenous_tuple_float():
90+
def homogeneous_tuple_float():
8891
ai = (1.5, 4.3, 5.2, 7.2, 9.999)
89-
return ai[0], ai[1], ai[2], ai[3], ai[4]
92+
i = 1
93+
return ai[0], ai[i], ai[2], ai[3], ai[4]
9094

91-
def homogenous_tuple_string():
95+
def homogeneous_tuple_string():
9296
ai = ('hello', 'tuple', 'world', '!!')
93-
return ai[0], ai[1], ai[2], ai[3]
97+
i = 1
98+
return ai[0], ai[i], ai[2], ai[3]
9499

95-
def homogenous_tuple_math():
100+
def homogeneous_tuple_math():
96101
ai = (4+5,3*9, 2**3)
97-
return ai[0], ai[1], ai[2]
102+
i = 1
103+
return ai[0], ai[i], ai[2]
98104

99-
def inhomogenous_tuple_1():
105+
def homogeneous_tuple_containing_var():
106+
elem = 4
107+
ai = (1, elem, 5)
108+
i = 1
109+
return ai[0], ai[i], ai[2]
110+
111+
def inhomogeneous_tuple_1():
100112
ai = (0, False, 3+1j)
101113
return ai[0], ai[1], ai[2]
102114

103-
def inhomogenous_tuple_2():
115+
def inhomogeneous_tuple_2():
104116
ai = (0, False, 3)
105117
return ai[0], ai[1], ai[2]
106118

107-
def inhomogenous_tuple_3():
119+
def inhomogeneous_tuple_3():
108120
ai = (0, 1.0, 3)
109121
return ai[0], ai[1], ai[2]
110122

111-
def inhomogenous_tuple_2_levels_1():
123+
def inhomogeneous_tuple_2_levels_1():
112124
# TODO [EB 15.06.21] Put back original test when strings are supported in C
113125
#ai = ((1,2), (4,False), (3.0, 'boo'))
114126
ai = ((1,2), (4,False), (3.0, True))
115127
return ai[0][0], ai[0][1], ai[1][0], ai[1][1], ai[2][0]
116128

117-
def inhomogenous_tuple_2_levels_2():
129+
def inhomogeneous_tuple_2_levels_2():
118130
ai = ((0,1,2), (True,False,True))
119131
return ai[0][0], ai[0][1] ,ai[0][2], ai[1][0], ai[1][1], ai[1][2]
120132

@@ -270,23 +282,27 @@ def tuples_inhomogeneous_copies_have_pointers():
270282
def tuples_mul_homogeneous():
271283
a = (1,2,3)
272284
b = a*2
273-
return b[0], b[1], b[2], b[3], b[4], b[5]
285+
i = 1
286+
return b[0], b[i], b[2], b[3], b[4], b[5]
274287

275288
def tuples_mul_homogeneous2():
276289
a = (1,2,3)
277290
b = 2*a
278-
return b[0], b[1], b[2], b[3], b[4], b[5]
291+
i = 1
292+
return b[0], b[i], b[2], b[3], b[4], b[5]
279293

280294
def tuples_mul_homogeneous3():
281295
a = (1,2,3)
282296
s = 2
283297
b = a*s
284-
return b[0], b[1], b[2], b[3], b[4], b[5]
298+
i = 1
299+
return b[0], b[i], b[2], b[3], b[4], b[5]
285300

286301
def tuples_mul_homogeneous4():
287302
s = 2
288303
b = (1,2,3)*s
289-
return b[0], b[1], b[2], b[3], b[4], b[5]
304+
i = 1
305+
return b[0], b[i], b[2], b[3], b[4], b[5]
290306

291307
def tuples_mul_inhomogeneous():
292308
a = (1,False)
@@ -318,23 +334,27 @@ def tuples_mul_inhomogeneous_2d():
318334

319335
def tuples_add_homogeneous():
320336
a = (1,2,3) + (4,5,6)
321-
return a[0], a[1], a[2], a[3], a[4], a[5]
337+
i = 1
338+
return a[0], a[i], a[2], a[3], a[4], a[5]
322339

323340
def tuples_add_homogeneous_variables():
324341
a = (1,2,3)
325342
b = (4,5,6)
326343
c = a + b
327-
return c[0], c[1], c[2], c[3], c[4], c[5]
344+
i = 1
345+
return c[0], c[i], c[2], c[3], c[4], c[5]
328346

329347
def tuples_add_homogeneous_with_variables():
330348
a = (1,2,3)
331349
c = a + (4,5,6)
332-
return c[0], c[1], c[2], c[3], c[4], c[5]
350+
i = 1
351+
return c[0], c[i], c[2], c[3], c[4], c[5]
333352

334353
def tuples_add_homogeneous_with_variables2():
335354
a = (1,2,3)
336355
c = (4,5,6) + a
337-
return c[0], c[1], c[2], c[3], c[4], c[5]
356+
i = 1
357+
return c[0], c[i], c[2], c[3], c[4], c[5]
338358

339359
def tuples_add_inhomogeneous():
340360
a = (1,2,True) + (False,5,6)
@@ -374,7 +394,8 @@ def tuples_add_mixed_homogeneous_with_variables():
374394
def tuples_2d_sum():
375395
a = ((1,2), (3,4))
376396
b = a + ((5,6),)
377-
return b[0][0], b[0][1], b[1][0], b[1][1], b[2][0], b[2][1]
397+
i = 1
398+
return b[0][0], b[0][i], b[1][0], b[i][i], b[2][0], b[2][1]
378399

379400
def tuples_func():
380401
def my_tup():
@@ -410,23 +431,28 @@ def tuple_index():
410431

411432
def tuple_homogeneous_int():
412433
a = tuple((1, 2, 3))
413-
return a[0], a[1], a[2], len(a)
434+
i = 1
435+
return a[0], a[i], a[2], len(a)
414436

415437
def tuple_homogeneous_bool():
416438
a = tuple((False, True))
417-
return a[0], a[1], len(a)
439+
i = 1
440+
return a[0], a[i], len(a)
418441

419442
def tuple_homogeneous_float():
420443
a = tuple((1.5, 4.3, 5.2, 7.2, 9.999))
421-
return a[0], a[1], a[2], a[3], a[4], len(a)
444+
i = 1
445+
return a[0], a[i], a[2], a[3], a[4], len(a)
422446

423447
def tuple_homogeneous_string():
424448
a = tuple(('hello', 'tuple', 'world', '!!'))
425-
return a[0], a[1], a[2], a[3], len(a)
449+
i = 1
450+
return a[0], a[i], a[2], a[3], len(a)
426451

427452
def tuple_homogeneous_math():
428453
a = tuple((4 + 5, 3 * 9, 2 ** 3))
429-
return a[0], a[1], a[2], len(a)
454+
i = 1
455+
return a[0], a[i], a[2], len(a)
430456

431457
def tuple_inhomogeneous_1():
432458
a = tuple((0, False, 3 + 1j))

tests/epyccel/test_tuples.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def is_func_with_0_args(f):
1717
if is_func_with_0_args(f)]
1818

1919
failing_tests = {
20-
'homogenous_tuple_string':'String has no precision',
20+
'homogeneous_tuple_string':"Can't save a list of strings (#459)",
2121
'tuple_homogeneous_return':"Can't return a tuple",
2222
'tuple_inhomogeneous_return':"Can't return a tuple",
2323
'tuple_visitation_inhomogeneous':"Can't iterate over an inhomogeneous tuple",

0 commit comments

Comments
 (0)