Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use Logging | |
| 3 | ||
| 4 | use Semantic.LEAST_UPPER_BOUND_MAP | |
| 5 | use Semantic.Types.Type | |
| 6 | ||
| 7 | // Settles a loop expression's result type from its valued-`break` | |
| 8 | // contributions: the LUB of the contributions — falling back to the | |
| 9 | // pushed expected type when nothing usable contributes — widened to | |
| 10 | // the optional form of the element kind. Widening follows the same | |
| 11 | // per-kind split as if/case arm joins: NULLABLE[T] for a value | |
| 12 | // type, MAYBE[T] for an unconstrained type parameter where the | |
| 13 | // runtime assembly is available (the flagged reference optional as | |
| 14 | // the fallback when it is not), the flagged reference optional for | |
| 15 | // any other reference kind. An already-optional LUB stands. | |
| 16 | // | |
| 17 | // The three optional makers are injected: they depend on reflected | |
| 18 | // runtime assemblies that unit-test fixtures do not load, and the | |
| 19 | // contract under test is which maker fires for which element kind, | |
| 20 | // not how each optional is constructed. | |
| 21 | class LOOP_RESULT_SETTLER is | |
| 22 | _make_nullable: (Type) -> Type | |
| 23 | _make_maybe: (Type) -> Type? | |
| 24 | _make_reference_optional: (Type) -> Type | |
| 25 | ||
| 26 | init( | |
| 27 | make_nullable: (Type) -> Type, | |
| 28 | make_maybe: (Type) -> Type?, | |
| 29 | make_reference_optional: (Type) -> Type | |
| 30 | ) is | |
| 31 | _make_nullable = make_nullable | |
| 32 | _make_maybe = make_maybe | |
| 33 | _make_reference_optional = make_reference_optional | |
| 34 | si | |
| 35 | ||
| 36 | // Null means "cannot infer" — contributions empty or all-error, | |
| 37 | // with no expected type — for the caller to report against the | |
| 38 | // loop's own location. | |
| 39 | settle(contributions: Collections.Iterable[Type], expected: Type?) -> Type? is | |
| 40 | let lub = LEAST_UPPER_BOUND_MAP() | |
| 41 | ||
| 42 | let saw_contribution mut = false | |
| 43 | ||
| 44 | for t in contributions do | |
| 45 | if !t.is_error then | |
| 46 | lub.add(t) | |
| 47 | ||
| 48 | saw_contribution = true | |
| 49 | fi | |
| 50 | od | |
| 51 | ||
| 52 | if !saw_contribution then | |
| 53 | return expected | |
| 54 | fi | |
| 55 | ||
| 56 | let inner mut = lub.get_result() ?? expected | |
| 57 | ||
| 58 | if !inner? then | |
| 59 | return null | |
| 60 | fi | |
| 61 | ||
| 62 | if inner.is_optional then | |
| 63 | return inner | |
| 64 | fi | |
| 65 | ||
| 66 | if inner.is_type_variable then | |
| 67 | return _make_maybe(inner) ?? _make_reference_optional(inner) | |
| 68 | elif inner.is_value_type then | |
| 69 | return _make_nullable(inner) | |
| 70 | fi | |
| 71 | ||
| 72 | return _make_reference_optional(inner) | |
| 73 | si | |
| 74 | si | |
| 75 | si |