Skip to content

Commit 49cb8af

Browse files
alexisthedevtheosotr
authored andcommitted
Pass and generate union types with previously generated types
1 parent 8aa2dd1 commit 49cb8af

File tree

3 files changed

+48
-19
lines changed

3 files changed

+48
-19
lines changed

src/generators/generator.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def __init__(self,
6161
self.function_types = self.bt_factory.get_function_types(
6262
cfg.limits.max_functional_params)
6363

64-
self.ret_builtin_types = self.bt_factory.get_non_nothing_types(self)
64+
self.ret_builtin_types = self.bt_factory.get_non_nothing_types()
6565
self.builtin_types = self.ret_builtin_types + \
6666
[self.bt_factory.get_void_type()]
6767

@@ -1895,7 +1895,7 @@ def gen_fun_call(etype):
18951895
),
18961896
self.bt_factory.get_null_type().name: lambda x: ast.Null
18971897
}
1898-
constant_candidates.update(self.bt_factory.get_constant_candidates(self, constant_candidates))
1898+
constant_candidates.update(self.bt_factory.get_constant_candidates(constant_candidates))
18991899
binary_ops = {
19001900
self.bt_factory.get_boolean_type(): [
19011901
lambda x: self.gen_logical_expr(x, only_leaves),
@@ -1981,7 +1981,6 @@ def get_types(self,
19811981
if exclude_contravariants and variance == tp.Contravariant:
19821982
continue
19831983
type_params.append(t_param)
1984-
19851984
if type_params and ut.random.bool():
19861985
return type_params
19871986

@@ -1993,9 +1992,11 @@ def get_types(self,
19931992
t for t in builtins
19941993
if t.name != self.bt_factory.get_array_type().name
19951994
]
1995+
1996+
dynamic = self.bt_factory.get_dynamic_types(self)
19961997
if exclude_function_types:
1997-
return usr_types + builtins
1998-
return usr_types + builtins + self.function_types
1998+
return usr_types + builtins + dynamic
1999+
return usr_types + builtins + dynamic + self.function_types
19992000

20002001
def select_type(self,
20012002
ret_types=True,

src/ir/builtins.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def get_function_type(self, nr_parameters=0):
8181
def get_null_type(self):
8282
pass
8383

84-
def get_non_nothing_types(self, gen_object):
84+
def get_non_nothing_types(self):
8585
return [
8686
self.get_any_type(),
8787
self.get_number_type(),
@@ -138,9 +138,19 @@ def get_function_types(self, max_parameters):
138138
def get_nothing(self):
139139
raise NotImplementedError
140140

141-
def get_constant_candidates(self):
141+
def get_dynamic_types(self, gen_object):
142+
""" A type is considered dynamic if it can utilize
143+
both a builtin type and a user-defined type.
144+
145+
Eg. A TypeScript Union Type: string | myClass
146+
147+
"""
148+
return []
149+
150+
def get_constant_candidates(self, constants):
142151
""" Overwrite this function to update the generator
143152
constants with language-specific.
153+
144154
"""
145155
return {}
146156

src/ir/typescript_types.py

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,11 @@ def get_big_decimal_type(self):
7777
def get_null_type(self):
7878
return NullType(primitive=False)
7979

80-
def get_non_nothing_types(self, gen_object): # Overwriting Parent method to add TS-specific types
81-
types = super().get_non_nothing_types(gen_object)
80+
def get_non_nothing_types(self): # Overwriting Parent method to add TS-specific types
81+
types = super().get_non_nothing_types()
8282
types.extend([
8383
self.get_null_type(),
8484
UndefinedType(primitive=False),
85-
union_types.get_union_type(gen_object),
8685
] + literal_types.get_literal_types())
8786
return types
8887

@@ -94,7 +93,12 @@ def update_add_node_to_parent(self):
9493
ts_ast.TypeAliasDeclaration: add_type_alias,
9594
}
9695

97-
def get_constant_candidates(self, gen_object, constants):
96+
def get_dynamic_types(self, gen_object):
97+
return [
98+
union_types.get_union_type(gen_object),
99+
]
100+
101+
def get_constant_candidates(self, constants):
98102
""" Updates the constant candidates of the generator
99103
with the type-constant pairs for language-specific features.
100104
@@ -432,6 +436,11 @@ def __init__(self, types, name="UnionType", primitive=False):
432436
def get_types(self):
433437
return self.types
434438

439+
def is_assignable(self, other):
440+
# TODO revisit this after implementing structural types
441+
return (isinstance(other, UnionType) and
442+
set(other.types) == set(self.types))
443+
435444
def get_name(self):
436445
return self.name
437446

@@ -452,21 +461,24 @@ def __init__(self, max_ut, max_in_union):
452461
else len(self.candidates))
453462

454463
def get_number_of_types(self):
455-
# TODO Perhaps make this user configurable
456464
return ut.random.integer(2, self.max_in_union)
457465

458-
def gen_union_type(self):
466+
def gen_union_type(self, gen):
459467
""" Generates a union type that consists of
460468
N types (where N is num_of_types).
461469
462470
Args:
463471
num_of_types - Number of types to be unionized
472+
gen - Instance of Hephaestus' generator
464473
"""
465-
# TODO | generate union types with previously
466-
# TODO | generated types (ie. classes, type aliases)
467474
num_of_types = self.get_number_of_types()
468475
assert num_of_types < len(self.candidates)
469476
types = self.candidates.copy()
477+
usr_types = [
478+
c.get_type()
479+
for c in gen.context.get_classes(gen.namespace).values()
480+
]
481+
types.extend(usr_types)
470482
ut.random.shuffle(types)
471483
types = types[0:num_of_types]
472484
gen_union = UnionType(types)
@@ -485,21 +497,27 @@ def get_union_type(self, gen_object):
485497
"""
486498
generated = len(self.unions)
487499
if generated == 0:
488-
return self.gen_union_type()
500+
return self.gen_union_type(gen_object)
489501
if generated >= self.max_ut or ut.random.bool():
490502
return ut.random.choice(self.unions)
491-
return self.gen_union_type()
503+
return self.gen_union_type(gen_object)
492504

493505
def get_union_constant(self, utype, constants):
494-
type_candidates = [t for t in utype.types if t.name in constants]
495-
""" A union type can have types like 'Object' or 'undefined'
506+
""" This method randomly chooses one of the types in a type's
507+
union and then assigns the union a constant value that matches
508+
the randomly selected type.
509+
510+
A union type can have types like 'Object' or 'undefined'
496511
as part of its union, which however do not have a respective
497512
constant equivalent.
498513
499514
Hence, we only consider types that we can generate a constant
500515
from. If there is none, we revert to a bottom constant.
501516
517+
TODO revisit this after implementing structural types.
518+
502519
"""
520+
type_candidates = [t for t in utype.types if t.name in constants]
503521
if len(type_candidates) == 0:
504522
return ast.BottomConstant(utype.types[0])
505523
t = ut.random.choice(type_candidates)

0 commit comments

Comments
 (0)