Appearance
| 1 | namespace Semantic is | |
| 2 | use Source.LOCATION | |
| 3 | ||
| 4 | use Types.Type | |
| 5 | ||
| 6 | // What one `await` reaches on its operand: the operand's | |
| 7 | // `get_awaiter`, and on the awaiter that returns, `is_completed` | |
| 8 | // and `get_result`. The result type of the `await` is whatever | |
| 9 | // `get_result` returns, void included. | |
| 10 | class AWAITABLE is | |
| 11 | awaiter_type: Type | |
| 12 | get_awaiter: Symbols.Function | |
| 13 | is_completed: Symbols.Function | |
| 14 | get_result: Symbols.Function | |
| 15 | ||
| 16 | // The awaiter implements `ICriticalNotifyCompletion`, so the | |
| 17 | // continuation is registered through the builder's | |
| 18 | // `AwaitUnsafeOnCompleted`; otherwise through | |
| 19 | // `AwaitOnCompleted`. | |
| 20 | is_critical: bool | |
| 21 | ||
| 22 | result_type: Type => get_result.return_type! | |
| 23 | ||
| 24 | init( | |
| 25 | awaiter_type: Type, | |
| 26 | get_awaiter: Symbols.Function, | |
| 27 | is_completed: Symbols.Function, | |
| 28 | get_result: Symbols.Function, | |
| 29 | is_critical: bool | |
| 30 | ) is | |
| 31 | self.awaiter_type = awaiter_type | |
| 32 | self.get_awaiter = get_awaiter | |
| 33 | self.is_completed = is_completed | |
| 34 | self.get_result = get_result | |
| 35 | self.is_critical = is_critical | |
| 36 | si | |
| 37 | si | |
| 38 | ||
| 39 | // Resolves the awaiter pattern against an operand type by member | |
| 40 | // lookup, the way C# does: a parameterless `get_awaiter` whose | |
| 41 | // result has a `bool` property `is_completed`, a parameterless | |
| 42 | // `get_result`, and implements `INotifyCompletion`. Nothing here | |
| 43 | // is specific to `Task`; a `ValueTask`, `Tasks.TASK.yield()` or | |
| 44 | // a user-defined awaitable resolves the same way. | |
| 45 | // | |
| 46 | // `resolve` reports one error naming the first missing piece and | |
| 47 | // returns null; the caller substitutes an error-typed value. | |
| 48 | // `try_resolve` answers the same question silently, for a caller | |
| 49 | // asking whether a value could be awaited rather than awaiting it. | |
| 50 | class AWAITABLE_RESOLVER( | |
| 51 | _innate_symbol_lookup: Lookups.InnateSymbolLookup, | |
| 52 | _logger: Logging.Logger | |
| 53 | ) is | |
| 54 | resolve(location: LOCATION, type: Type) -> AWAITABLE? => | |
| 55 | _resolve(location, type, true) | |
| 56 | ||
| 57 | try_resolve(type: Type) -> AWAITABLE? => | |
| 58 | _resolve(LOCATION.internal, type, false) | |
| 59 | ||
| 60 | _resolve(location: LOCATION, type: Type, report: bool) -> AWAITABLE? is | |
| 61 | // An operand whose type failed to resolve has already been | |
| 62 | // reported where the failure was. | |
| 63 | if type.is_error then | |
| 64 | return null | |
| 65 | fi | |
| 66 | ||
| 67 | let get_awaiter = _zero_argument_function(type, "get_awaiter") | |
| 68 | ||
| 69 | if !get_awaiter? then | |
| 70 | return _fail(report, location, "cannot await {type}: no get_awaiter method") | |
| 71 | fi | |
| 72 | ||
| 73 | let awaiter_type = get_awaiter.return_type | |
| 74 | ||
| 75 | if !awaiter_type? \/ awaiter_type.is_void then | |
| 76 | return _fail(report, location, "cannot await {type}: get_awaiter returns no value") | |
| 77 | fi | |
| 78 | ||
| 79 | let is_completed = _property_getter(awaiter_type, "is_completed") | |
| 80 | ||
| 81 | if !is_completed? then | |
| 82 | return _fail(report, location, "cannot await {type}: awaiter {awaiter_type} has no is_completed property") | |
| 83 | fi | |
| 84 | ||
| 85 | let is_completed_type = is_completed.return_type | |
| 86 | ||
| 87 | if !is_completed_type? \/ !is_completed_type.is_equivalent_to(_innate_symbol_lookup.get_bool_type()) then | |
| 88 | return _fail(report, location, "cannot await {type}: awaiter {awaiter_type} is_completed is not bool") | |
| 89 | fi | |
| 90 | ||
| 91 | let get_result = _zero_argument_function(awaiter_type, "get_result") | |
| 92 | ||
| 93 | if !get_result? then | |
| 94 | return _fail(report, location, "cannot await {type}: awaiter {awaiter_type} has no get_result method") | |
| 95 | fi | |
| 96 | ||
| 97 | if !get_result.return_type? then | |
| 98 | return _fail(report, location, "cannot await {type}: awaiter {awaiter_type} get_result has no return type") | |
| 99 | fi | |
| 100 | ||
| 101 | let is_critical = _implements(awaiter_type, _innate_symbol_lookup.get_critical_notify_completion_type()) | |
| 102 | ||
| 103 | if !is_critical /\ !_implements(awaiter_type, _innate_symbol_lookup.get_notify_completion_type()) then | |
| 104 | return _fail(report, location, "cannot await {type}: awaiter {awaiter_type} does not implement System.Runtime.CompilerServices.INotifyCompletion") | |
| 105 | fi | |
| 106 | ||
| 107 | return AWAITABLE(awaiter_type, get_awaiter, is_completed, get_result, is_critical) | |
| 108 | si | |
| 109 | ||
| 110 | _fail(report: bool, location: LOCATION, message: string) -> AWAITABLE? is | |
| 111 | if report then | |
| 112 | _logger.error(location, message) | |
| 113 | fi | |
| 114 | ||
| 115 | return null | |
| 116 | si | |
| 117 | ||
| 118 | _implements(type: Type, interface: Type?) -> bool => | |
| 119 | interface? /\ interface.is_assignable_from(type) | |
| 120 | ||
| 121 | // Each member is called on a receiver, so only an instance | |
| 122 | // member with no parameters qualifies; a static of the same | |
| 123 | // name is not part of the pattern. | |
| 124 | _zero_argument_function(type: Type, name: string) -> Symbols.Function? is | |
| 125 | if let group: Symbols.FUNCTION_GROUP = type.find_member(name) then | |
| 126 | for f in group.functions do | |
| 127 | if f.is_instance /\ f.arguments.count == 0 then | |
| 128 | return f | |
| 129 | fi | |
| 130 | od | |
| 131 | fi | |
| 132 | ||
| 133 | return null | |
| 134 | si | |
| 135 | ||
| 136 | _property_getter(type: Type, name: string) -> Symbols.Function? is | |
| 137 | if let property: Symbols.Property = type.find_member(name) then | |
| 138 | if let getter = property.read_function /\ getter.is_instance then | |
| 139 | return getter | |
| 140 | fi | |
| 141 | fi | |
| 142 | ||
| 143 | return null | |
| 144 | si | |
| 145 | si | |
| 146 | si |