Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use System.Exception | |
| 3 | ||
| 4 | use Ghul.Pipes | |
| 5 | ||
| 6 | use Logging | |
| 7 | use Trees | |
| 8 | ||
| 9 | use Semantic.Types.Type | |
| 10 | ||
| 11 | use Function = Semantic.Symbols.Function | |
| 12 | use Symbol = Semantic.Symbols.Symbol | |
| 13 | ||
| 14 | // Callee-edge construction: callee and construction-callee lists, dispatch edges, | |
| 15 | // property-read edges and member reads. | |
| 16 | partial INFER_STORE_FREE is | |
| 17 | _add_callee(callee: Function?) is | |
| 18 | if !_current? then | |
| 19 | return | |
| 20 | fi | |
| 21 | ||
| 22 | if !callee? then | |
| 23 | _disqualify_because("callee-null") | |
| 24 | return | |
| 25 | fi | |
| 26 | ||
| 27 | let root = cast Function?(callee.root_specialized_from) | |
| 28 | ||
| 29 | if !root? then | |
| 30 | _disqualify_because("callee-no-root") | |
| 31 | return | |
| 32 | fi | |
| 33 | ||
| 34 | _current.add_callee(root) | |
| 35 | si | |
| 36 | ||
| 37 | _add_construction_callee(callee: Function?) is | |
| 38 | if !_current? then | |
| 39 | return | |
| 40 | fi | |
| 41 | ||
| 42 | if !callee? then | |
| 43 | _disqualify_because("ctor-callee-null") | |
| 44 | return | |
| 45 | fi | |
| 46 | ||
| 47 | let root = cast Function?(callee.root_specialized_from) | |
| 48 | ||
| 49 | if !root? then | |
| 50 | _disqualify_because("ctor-callee-no-root") | |
| 51 | return | |
| 52 | fi | |
| 53 | ||
| 54 | _current.add_construction_callee(root) | |
| 55 | si | |
| 56 | ||
| 57 | _add_callee_edges(symbol: Symbol?) is | |
| 58 | if !_current? then | |
| 59 | return | |
| 60 | fi | |
| 61 | ||
| 62 | if !symbol? then | |
| 63 | _disqualify_because("callee-symbol-null") | |
| 64 | return | |
| 65 | fi | |
| 66 | ||
| 67 | if isa Semantic.Symbols.FUNCTION_GROUP(symbol) then | |
| 68 | for function in (cast Semantic.Symbols.FUNCTION_GROUP(symbol)).functions do | |
| 69 | _add_callee(function) | |
| 70 | od | |
| 71 | elif isa Function(symbol) then | |
| 72 | _add_callee(cast Function(symbol)) | |
| 73 | elif | |
| 74 | _resolved_mode /\ | |
| 75 | isa Semantic.Symbols.LOCAL_ARGUMENT(symbol) /\ | |
| 76 | symbol.type? /\ symbol.type.is_function | |
| 77 | then | |
| 78 | // invoking a function-typed parameter: bounded by the | |
| 79 | // values the enclosing function's own callers pass | |
| 80 | if _current_record? then | |
| 81 | _current_record.invokes_function_param = true | |
| 82 | fi | |
| 83 | elif _is_store_free_construction(symbol) then | |
| 84 | // constructing a fresh exception writes only that new | |
| 85 | // object, never a pre-existing heap slot, so it cannot | |
| 86 | // invalidate a narrowing | |
| 87 | elif isa Semantic.Symbols.Classy(symbol) /\ !symbol.is_reflected then | |
| 88 | _add_construction_edges((cast Semantic.Symbols.Classy(symbol)).find_member("init")) | |
| 89 | else | |
| 90 | // a delegate-typed value, an imported constructor, or | |
| 91 | // something stranger: the call's effect cannot be | |
| 92 | // bounded | |
| 93 | _disqualify_because("callee-not-a-function:{symbol.get_type().name}") | |
| 94 | fi | |
| 95 | si | |
| 96 | ||
| 97 | // Constructing a source-declared type runs a constructor on an | |
| 98 | // object nothing else can reach yet, so the caller is bounded | |
| 99 | // by the constructor's construction-store-free classification | |
| 100 | // rather than its strict one — a constructor writing its own | |
| 101 | // instance state stays store-free from where the construction | |
| 102 | // is written. Overload resolution has not run, so every `init` | |
| 103 | // the type declares has to qualify. | |
| 104 | _add_construction_edges(constructors: Symbol?) is | |
| 105 | if isa Semantic.Symbols.FUNCTION_GROUP(constructors) then | |
| 106 | for function in (cast Semantic.Symbols.FUNCTION_GROUP(constructors)).functions do | |
| 107 | _add_construction_callee(function) | |
| 108 | od | |
| 109 | ||
| 110 | return | |
| 111 | fi | |
| 112 | ||
| 113 | if isa Function(constructors) then | |
| 114 | _add_construction_callee(cast Function(constructors)) | |
| 115 | return | |
| 116 | fi | |
| 117 | ||
| 118 | _disqualify_because("constructor-unresolved") | |
| 119 | si | |
| 120 | ||
| 121 | // Constructing an imported exception type is store-free for | |
| 122 | // narrowing: an exception constructor by .NET convention only | |
| 123 | // records its arguments into the new exception's own state and | |
| 124 | // invokes no behaviour on them, so no user code runs and no | |
| 125 | // pre-existing heap slot is written. The constructor arguments | |
| 126 | // are classified as the walk reaches them, so a storing | |
| 127 | // argument still disqualifies. Restricted to reflected types so | |
| 128 | // a user-declared exception - whose constructor could store - | |
| 129 | // stays unbounded. | |
| 130 | _is_store_free_construction(symbol: Symbol?) -> bool is | |
| 131 | if !symbol? \/ !symbol.is_reflected \/ !isa Semantic.Symbols.Classy(symbol) then | |
| 132 | return false | |
| 133 | fi | |
| 134 | ||
| 135 | let exception_type = _innate_symbol_lookup.get_exception_type() | |
| 136 | let classy_type = (cast Semantic.Symbols.Classy(symbol)).type | |
| 137 | ||
| 138 | return classy_type? /\ exception_type.is_assignable_from(classy_type) | |
| 139 | si | |
| 140 | ||
| 141 | // A property read runs its getter, and a call that reaches | |
| 142 | // the getter may dispatch to any overriding property's getter. | |
| 143 | // Property override links live on the Property symbols, not | |
| 144 | // on the accessor functions, so the override closure is | |
| 145 | // expanded here rather than through Function.overriders. | |
| 146 | _add_property_read_edges(property: Semantic.Symbols.Property) is | |
| 147 | if !_current? then | |
| 148 | return | |
| 149 | fi | |
| 150 | ||
| 151 | if !property.read_function? then | |
| 152 | _disqualify_because("property-no-getter") | |
| 153 | return | |
| 154 | fi | |
| 155 | ||
| 156 | _add_callee(property.read_function) | |
| 157 | ||
| 158 | let overriders = property.overriders | |
| 159 | ||
| 160 | if !overriders? then | |
| 161 | return | |
| 162 | fi | |
| 163 | ||
| 164 | for overrider in overriders do | |
| 165 | if isa Semantic.Symbols.Property(overrider) then | |
| 166 | _add_property_read_edges(cast Semantic.Symbols.Property(overrider)) | |
| 167 | else | |
| 168 | _disqualify_because("overrider-not-a-property") | |
| 169 | fi | |
| 170 | od | |
| 171 | si | |
| 172 | ||
| 173 | _classify_member_read(symbol: Symbol?) is | |
| 174 | if !symbol? then | |
| 175 | return | |
| 176 | fi | |
| 177 | ||
| 178 | if isa Semantic.Symbols.Property(symbol) then | |
| 179 | _add_property_read_edges(cast Semantic.Symbols.Property(symbol)) | |
| 180 | fi | |
| 181 | ||
| 182 | // fields, locals, parameters, function groups (a bare | |
| 183 | // function reference only creates a delegate), types and | |
| 184 | // namespaces are harmless reads | |
| 185 | ||
| 186 | if | |
| 187 | _current_record? /\ | |
| 188 | (isa Semantic.Symbols.Field(symbol) \/ isa Semantic.Symbols.Property(symbol)) | |
| 189 | then | |
| 190 | _current_record.reads.add(symbol.root_specialized_from) | |
| 191 | fi | |
| 192 | si | |
| 193 | ||
| 194 | si | |
| 195 | si |