Appearance
| 1 | namespace Semantic.Types is | |
| 2 | ||
| 3 | class NULL: Type is | |
| 4 | is_null: bool => true | |
| 5 | ||
| 6 | // The type of the `null` literal is an optional type - it is | |
| 7 | // the one value every optional type has and no other type | |
| 8 | // does. Saying so here is what lets the ordinary rule that a | |
| 9 | // non-optional slot rejects an optional value carry the | |
| 10 | // literal too, rather than each slot testing for null. | |
| 11 | is_optional: bool => true | |
| 12 | ||
| 13 | init() is | |
| 14 | super.init() | |
| 15 | si | |
| 16 | ||
| 17 | specialize(type_map: Collections.Map[Symbols.Symbol,Type]) -> Type => self | |
| 18 | ||
| 19 | matches(other: Type) -> bool | |
| 20 | => true | |
| 21 | ||
| 22 | // Only an optional slot takes a `null`. A type variable stays | |
| 23 | // assignable: an unconstrained `T` can still be instantiated | |
| 24 | // at an optional type. Sentinels stay assignable so a type | |
| 25 | // that is already broken, or not yet inferred, does not draw a | |
| 26 | // second diagnostic here. | |
| 27 | compare(other: Type) -> Types.MATCH => | |
| 28 | if | |
| 29 | other.is_sentinel \/ other.is_type_variable \/ other.is_optional | |
| 30 | then | |
| 31 | MATCH.ASSIGNABLE | |
| 32 | else | |
| 33 | MATCH.DIFFERENT | |
| 34 | fi | |
| 35 | ||
| 36 | to_string() -> string => "null" | |
| 37 | si | |
| 38 | si |