~jasper/type_stack_calc

fe1ae9a8389aa354af54d0778fa119d3e9037bea — Jasper den Ouden 9 months ago cbb1b76
Complaining about type calculating of recursion not being correct, some changes there. Minor change in test, comments
M test/sets/intersection.py => test/sets/intersection.py +3 -1
@@ 45,8 45,10 @@ check([r(0,10), s(0,1)], [r(3,3)],
      ('subtract',  [r(-3,7), s(0,1)]),
      ('gt',   [b(None)]))  # TODO need to move boolean into sets.

print(si(r(0,1), s(0,1)))

import random  # Add constant, hammer more.
for x in [0] + [random.randint(-20,20) for _i in range(10)]:
for x in [0, 1] + [random.randint(-20,20) for _i in range(10)]:
    check([r(0,10), s(0,1)], [r(x, x)],
          ('mult', [rm(0,x*10), s(0, abs(x))] if x!=0 else [r(0,0)]),
          ('add',  [r(x,10+x), s(0,1)]),

M type_stack_calc/base/variant_able_function.py => type_stack_calc/base/variant_able_function.py +5 -2
@@ 23,10 23,13 @@ Provides just `.ensure_variant`"""
        key = types_key(inp)
        vdict = getattr(self, f"variants_{code_name}")
        variant = vdict.get(key)
        if variant is None:
        # NOTE: function-recursion (loops) shouldn't happen it will just
        #  produce the existing variant.
        if variant is None:  
            variant = TCVariant(code_name, self, inp, depth)
            vdict[key] = variant  # Remember it,
            variant.variant_tp_calc(real)  # AFTER type calculate, it may refer back to the remembered.
            variant.variant_tp_calc(real)
            # AFTER type calculate, it may refer back to the remembered.

        return variant


M type_stack_calc/ib/tc_variant.py => type_stack_calc/ib/tc_variant.py +22 -9
@@ 53,6 53,8 @@ class TCVariant(Ided, BaseFunctionVariant):
            f"Reached max depth of function calls at {depth}\n ({self})"
        self.c_id = None  # C output ID.

        self.unfinished = None  # Starts in invalid finishing state.

    @property
    def n(self): return len(self.parent.args)
    @property


@@ 70,9 72,13 @@ class TCVariant(Ided, BaseFunctionVariant):
        return getattr(self.parent, f"code_{self.code_name}") 

# TODO in some cases no interest in tc_code, just the calculated type.

# TODO make it actually correct.
#  + If it received an `TpUnknown` or changes, it's unresolved-distance is 0 
#  + Otherwise it's the smallest distance of stuff it called, plus one. If none, the distance is infinite.
#  + If the distance is greater than the deepest depth of call, then it is finished.
#
# TODO it's wrong if more than one layer of recursion.
#  lets say two: the first one will keep returning TpUnknown(), and the second will accept it.
# So need to track depth of call and these distances. Note that if there is no recursion the bottom will get "infinite" as value, causing the next layer.. etc.
    def variant_tp_calc(self, real):
        """Calculates a type-compiled variant. (does hard work)"""
        self.notify_real(real)


@@ 93,7 99,6 @@ class TCVariant(Ided, BaseFunctionVariant):
        parent = self.parent
        max_try_cnt = getattr(parent, f"max_try_cnt_{self.code_name}")
        while True:  # Calculate types it until the type stabilizes. # TODO will it?
            prev_tp = tp
            # Variables, same ach time, other functions is what changes.
            vs = parent.scope.sub(True, zip(args, inp), depth=self.depth + 1)
            vs.get_comp('~r').set(ReturnCatchType(self_id))


@@ 107,10 112,17 @@ class TCVariant(Ided, BaseFunctionVariant):
                tc_code = tc_code + [c1 for c1 in extra if c1 is not None]
            assert isinstance(vs['~r'].val, ReturnCatchType), vs['~r']
            tp = vs['~r'].val.ret_stack()   # Fill return type.
    
            self.ret_stack = tp   # Unchanged, result is good.
            if try_cnt > 0 and types_eq(prev_tp, tp):
                tc_code = [c1 for c1 in tc_code if c1 is not None]

            # TODO now what if loop of unfinished objects..
            tc_code = [c1 for c1 in tc_code if c1 is not None]
            objections = self.unfinished is None or \
                         any(getattr(c1, 'unfinished', None)
                             for c1 in tc_code)

            self.ret_stack = tp
            # If no longer changing and can finish now, it's good.
            if not objections and types_eq(self.unfinished, tp):
                self.unfinished = False
                self.tc_code = tc_code
                for el in tc_code:  # Keep count what's actually used.
                    if fun := getattr(el, 'notify_real', None): fun()


@@ 122,12 134,13 @@ class TCVariant(Ided, BaseFunctionVariant):
                    # NOTE/TODO if produce C code(compiled result) here
                    #  won't need it in any case?
                return
            self.unfinished = tp
            tc_code.clear()  # Reset code, or it will appear for each time.
            try_cnt += 1
            assert try_cnt < max_try_cnt, \
                f"""Hit max attempt count at {try_cnt} types versus previous:
{tp} vs {prev_tp}
{types_key(prev_tp)} vs {types_key(tp)}"""
{tp} vs {self.unfinished}
{types_key(self.unfinished)} vs {types_key(tp)}"""

    def notify_the_cc(self):  # TODO better name?
        """Locks all the `ComponentCollection`s made from here."""