Appearance
| 1 | namespace Semantic is | |
| 2 | use Types.Type | |
| 3 | ||
| 4 | // Recognises .NET delegate types and reports the function type that | |
| 5 | // describes how they are called. | |
| 6 | // | |
| 7 | // `Func` and `Action` are excluded: they are already modelled as | |
| 8 | // FUNCTION / ACTION, so `is_named_delegate` answers false for them | |
| 9 | // and callers keep their existing path. | |
| 10 | class DELEGATE_SHAPE is | |
| 11 | init() is | |
| 12 | si | |
| 13 | ||
| 14 | // True for a delegate type ghūl does not already model as a | |
| 15 | // function type. | |
| 16 | is_named_delegate(type: Type, innate_symbol_lookup: Lookups.InnateSymbolLookup) -> bool => | |
| 17 | !type.is_function /\ _inherits_multicast_delegate(type, innate_symbol_lookup) | |
| 18 | ||
| 19 | // The function type describing `type`'s call shape, or null when | |
| 20 | // `type` is not a named delegate or carries no usable `invoke`. | |
| 21 | try_get_function_type(type: Type, innate_symbol_lookup: Lookups.InnateSymbolLookup) -> Type? is | |
| 22 | if !is_named_delegate(type, innate_symbol_lookup) then | |
| 23 | return null | |
| 24 | fi | |
| 25 | ||
| 26 | let invoke = _find_invoke(type) | |
| 27 | ||
| 28 | if !invoke? \/ !invoke.return_type? \/ !invoke.are_arguments_declared then | |
| 29 | return null | |
| 30 | fi | |
| 31 | ||
| 32 | // Beyond the innate function-type shapes' own parameter | |
| 33 | // limit, no function type exists to describe this call | |
| 34 | // shape - answered here rather than by invoke.get_full_type, | |
| 35 | // which would report an error at the delegate's own | |
| 36 | // declaration instead of leaving this a quiet null probe. | |
| 37 | if invoke.arguments.count > Lookups.INNATE_TYPE_LIMITS.MAX_FUNCTION_PARAMETERS then | |
| 38 | return null | |
| 39 | fi | |
| 40 | ||
| 41 | return invoke.get_full_type(innate_symbol_lookup) | |
| 42 | si | |
| 43 | ||
| 44 | // Whether a function of `arity` parameters could be this | |
| 45 | // delegate. A delegate whose shape cannot be read is given the | |
| 46 | // benefit of the doubt. | |
| 47 | could_take_arity(type: Type, arity: int, innate_symbol_lookup: Lookups.InnateSymbolLookup) -> bool is | |
| 48 | let shape = try_get_function_type(type, innate_symbol_lookup) | |
| 49 | ||
| 50 | return !shape? \/ ARGUMENT_PACK.parameter_count(shape) == arity | |
| 51 | si | |
| 52 | ||
| 53 | // A delegate declares exactly one `Invoke`, so the group it | |
| 54 | // arrives in holds a single function. | |
| 55 | _find_invoke(type: Type) -> Symbols.Function? is | |
| 56 | let member = type.find_member("invoke") | |
| 57 | ||
| 58 | if let group: Symbols.FUNCTION_GROUP = member then | |
| 59 | if group.count == 1 then | |
| 60 | return group.functions[0] | |
| 61 | fi | |
| 62 | ||
| 63 | return null | |
| 64 | fi | |
| 65 | ||
| 66 | return cast Symbols.Function?(member) | |
| 67 | si | |
| 68 | ||
| 69 | // `System.MulticastDelegate` resolved from the lookup and | |
| 70 | // compared by symbol identity down the recursion — a rendered | |
| 71 | // name here would conflate a duplicate symbol rather than | |
| 72 | // resolve it. Null when the lookup cannot resolve it, in | |
| 73 | // which case nothing is a named delegate. | |
| 74 | _inherits_multicast_delegate(type: Type, innate_symbol_lookup: Lookups.InnateSymbolLookup) -> bool is | |
| 75 | let multicast = innate_symbol_lookup.get_multicast_delegate_type() | |
| 76 | ||
| 77 | if !multicast? then | |
| 78 | return false | |
| 79 | fi | |
| 80 | ||
| 81 | return _inherits(type, multicast.symbol) | |
| 82 | si | |
| 83 | ||
| 84 | _inherits(type: Type, multicast: Symbols.Symbol) -> bool is | |
| 85 | for ancestor in type.ancestors do | |
| 86 | if ancestor.symbol =~ multicast then | |
| 87 | return true | |
| 88 | fi | |
| 89 | ||
| 90 | if _inherits(ancestor, multicast) then | |
| 91 | return true | |
| 92 | fi | |
| 93 | od | |
| 94 | ||
| 95 | return false | |
| 96 | si | |
| 97 | si | |
| 98 | si |