Set '*result' to the index within 'type_dag' that contains an instance type bound by 'var' where free variables are instantiated * at the ONE type, recursively adding new nodes to 'type_dag' as necessary. * '*type_dag_used' will be incremented by the number of new 'type_dag' nodes created. * * If it is impossible to create a required instance (due to a cycle in the bindings reachable by 'var')
| 434 | * Postcondition: If 'true' is returned, then type type_dag[*type_dag_used] is well-formed |
| 435 | */ |
| 436 | static bool freeze(size_t* result, type* type_dag, size_t* type_dag_used, unification_var* var) { |
| 437 | var = findRoot(var); |
| 438 | |
| 439 | if (isFrozen(var)) { |
| 440 | *result = getFrozenIx(var); |
| 441 | return true; |
| 442 | } |
| 443 | |
| 444 | /* 'var' is not frozen, and therefore it must have a non-trivial binding. |
| 445 | * Create a one item stack of unification variables 'var' to be frozen. |
| 446 | */ |
| 447 | var->next = NULL; |
| 448 | simplicity_assert(!var->bound.occursCheck); |
| 449 | var->bound.occursCheck = true; |
| 450 | |
| 451 | /* Attempt to freeze all variables on the stack, pushing new variables onto the stack to recursively freeze them if needed. |
| 452 | * |
| 453 | * All variables in the stack are representatives of their equivalence class and have just had their 'occursCheck' flag changed |
| 454 | * from 'false' to 'true'. |
| 455 | * Variables never change their 'occursCheck' flag back from 'true' to 'false'. |
| 456 | * Variables are only removed from the stack after being frozen. |
| 457 | * Each time we go through this loop, the stack size either increases by 1 or decreases by 1. |
| 458 | * Therefore the total number of times this loop iterates summed over all calls to 'freeze' is bounded by |
| 459 | * twice the number of unification variable (representatives) with non-trivial bindings. |
| 460 | * ("twice" because once to add the variable to the stack and once to remove the variable from the stack). |
| 461 | * |
| 462 | * Note that number of unification_variables is bound linearly in the number of nodes in the Simplicity DAG. |
| 463 | */ |
| 464 | while (var) { |
| 465 | unification_var* typeArg[2] = { findRoot(var->bound.arg[0]), findRoot(var->bound.arg[1]) }; |
| 466 | if (!isFrozen(typeArg[0])) { |
| 467 | /* The first type argument's representative isn't frozen. Add it to the stack and immediately attempt to freeze it. */ |
| 468 | if (typeArg[0]->bound.occursCheck) return false; /* Occurs check failure. */ |
| 469 | typeArg[0]->bound.occursCheck = true; |
| 470 | typeArg[0]->next = var; |
| 471 | var = typeArg[0]; |
| 472 | } else if (!isFrozen(typeArg[1])) { |
| 473 | /* The second type argument's representative isn't frozen. Add it to the stack and immediately attempt to freeze it. */ |
| 474 | if (typeArg[1]->bound.occursCheck) return false; /* Occurs check failure. */ |
| 475 | typeArg[1]->bound.occursCheck = true; |
| 476 | typeArg[1]->next = var; |
| 477 | var = typeArg[1]; |
| 478 | } else { |
| 479 | /* Both the type argument's representatives are frozen. |
| 480 | * Create a new entry in the 'type_dag' for 'var's binding and freeze 'var'. |
| 481 | */ |
| 482 | *result = var->bound.frozen_ix = (*type_dag_used)++; |
| 483 | type_dag[var->bound.frozen_ix] = (type) |
| 484 | { .kind = var->bound.kind |
| 485 | , .typeArg = { getFrozenIx(typeArg[0]), getFrozenIx(typeArg[1]) } |
| 486 | }; |
| 487 | var = var->next; |
| 488 | } |
| 489 | } |
| 490 | |
| 491 | return true; |
| 492 | } |
| 493 |
no test coverage detected