Appearance
| 1 | namespace Semantic.Symbols is | |
| 2 | use Type = Semantic.Types.Type | |
| 3 | ||
| 4 | // Whether an imported function's parameters hand it any way to | |
| 5 | // reach either code declared in the assembly being built or | |
| 6 | // storage that existed before the call. | |
| 7 | // | |
| 8 | // Imported code can invoke only members it can name, and the names | |
| 9 | // available to it for an argument are those declared on the | |
| 10 | // parameter's own type. That type is never a type declared here, | |
| 11 | // so the only in-assembly code an argument can expose is an | |
| 12 | // override of a member the parameter's type already declares. | |
| 13 | // | |
| 14 | // The parameter types that expose nothing at all are named here | |
| 15 | // rather than derived, because the two plausible ways to derive | |
| 16 | // them are both wrong. Being a value type says nothing on its own: | |
| 17 | // a struct holds whatever its fields and type arguments hold, so | |
| 18 | // an `(object, object)` tuple hands over two references where an | |
| 19 | // `(int, int)` hands over none, and `Span[T]` or `ArraySegment[T]` | |
| 20 | // hands over a reference to storage the caller already owned. | |
| 21 | // Descending through the fields to find out fares no better, | |
| 22 | // because a struct whose members have not been materialized | |
| 23 | // presents as one with no fields, and absence of evidence would | |
| 24 | // read as evidence of safety in precisely the cases that matter. | |
| 25 | // | |
| 26 | // So the test is a positive one. A scalar and a `string` hold no | |
| 27 | // reference by construction, need no reflection to establish it, | |
| 28 | // and between them cover what imported constructors actually take. | |
| 29 | // Everything else declines, which costs a needless crossing and | |
| 30 | // nothing more. | |
| 31 | class IMPORT_ARGUMENTS is | |
| 32 | all_arguments_scalar(function: Function?) -> bool static is | |
| 33 | if !function? then | |
| 34 | return false | |
| 35 | fi | |
| 36 | ||
| 37 | for argument in function.arguments do | |
| 38 | if !_is_scalar(argument) then | |
| 39 | return false | |
| 40 | fi | |
| 41 | od | |
| 42 | ||
| 43 | return true | |
| 44 | si | |
| 45 | ||
| 46 | // A `ref` or pointer parameter is not a value type here, which | |
| 47 | // is what keeps the interpolated-string-handler overloads out. | |
| 48 | // A type variable is excluded explicitly: `GENERIC` reports | |
| 49 | // itself a value type unconditionally, and what a parameter | |
| 50 | // spelled as a bare `T` carries is settled by the | |
| 51 | // instantiation. | |
| 52 | _is_scalar(type: Type?) -> bool static is | |
| 53 | if !type? \/ type.is_type_variable then | |
| 54 | return false | |
| 55 | fi | |
| 56 | ||
| 57 | // An enum carries no reference and cannot be inherited, so | |
| 58 | // the members an imported callee can name on it are the | |
| 59 | // fixed BCL comparison and formatting code, and none of it | |
| 60 | // can reach code declared here. | |
| 61 | if isa ENUM_STRUCT(type.symbol) then | |
| 62 | return true | |
| 63 | fi | |
| 64 | ||
| 65 | let lookup = IoC.CONTAINER.instance.innate_symbol_lookup | |
| 66 | ||
| 67 | // string is sealed, so nothing declared here can override | |
| 68 | // anything the callee could name on it | |
| 69 | if !type.is_value_type then | |
| 70 | return type.matches(lookup.get_string_type()) | |
| 71 | fi | |
| 72 | ||
| 73 | return | |
| 74 | type.matches(lookup.get_bool_type()) \/ | |
| 75 | type.matches(lookup.get_char_type()) \/ | |
| 76 | type.matches(lookup.get_byte_type()) \/ | |
| 77 | type.matches(lookup.get_ubyte_type()) \/ | |
| 78 | type.matches(lookup.get_short_type()) \/ | |
| 79 | type.matches(lookup.get_ushort_type()) \/ | |
| 80 | type.matches(lookup.get_int_type()) \/ | |
| 81 | type.matches(lookup.get_uint_type()) \/ | |
| 82 | type.matches(lookup.get_long_type()) \/ | |
| 83 | type.matches(lookup.get_ulong_type()) \/ | |
| 84 | type.matches(lookup.get_word_type()) \/ | |
| 85 | type.matches(lookup.get_uword_type()) \/ | |
| 86 | type.matches(lookup.get_single_type()) \/ | |
| 87 | type.matches(lookup.get_double_type()) \/ | |
| 88 | type.matches(lookup.get_decimal_type()) | |
| 89 | si | |
| 90 | si | |
| 91 | si |