Intrinsics
An intrinsic is something the compiler implements itself: the arithmetic of int8, the value of float64::Infinity, the fields of #target, the code an Assert turns into. A program reaches it only through an intrinsic declaration, which names it and gives its type, with no body. The Core package holds the standard declarations, and every program imports them from there — import Core::{ #target, Assert, int8 }; — but Core has no special status: any package may declare the same intrinsics and be imported instead.
intrinsic-decl = [ "pub" ] "intrinsic" ( "type" identifier ";"
| "const" identifier ":" type ";"
| "#" identifier ":" type ";"
| function-signature ";" )
intrinsic const is written inside an extend block, and intrinsic func may be too, where it declares a method.
Four kinds
| Declaration | The compiler supplies | The provider writes |
|---|---|---|
intrinsic type int8; | the type and its operations | its constants and methods, as plain source |
intrinsic const Infinity: float64; | the value | the name and type, in an extend block |
intrinsic #target: Target; | each field the struct declares | the struct, with the fields it exposes |
intrinsic func Assert(…); | the code at every call | the exact signature the compiler expects |
A provider package, declaring a little of each:
// A type only the compiler can implement. Its constants are ordinary source.
pub intrinsic type int8;
extend int8 {
pub const Min: int8 = -128i8;
pub const Max: int8 = 127i8;
}
// A constant no literal can spell.
pub intrinsic type float64;
extend float64 {
pub intrinsic const Infinity: float64;
}
// A compiler-supplied value, exposing only the fields this provider chooses.
pub struct Target {
pub pointerBits: uint;
}
pub intrinsic #target: Target;
// Functions the compiler emits at each call.
pub intrinsic func Assert(condition: bool, message: char8[..]);
pub intrinsic func #Error(message: char8[..]);
A program that depends on it imports the same names it would otherwise take from Core, and works the same way:
import Basis::{ #target, #Error, Assert, float64, int8 };
func Main() -> int {
when #target.pointerBits < 64 {
#Error("needs a 64-bit target");
}
Assert(int8::Max == 127i8, "the provider's constant");
Assert(float64::Infinity > 1.0e308, "a compiler-supplied constant");
return 0;
}
Only what the provider declares is available: with Basis alone, int16 still exists as a type, but int16::Max does not.
Types
intrinsic type names an implemented primitive scalar in its canonical spelling — int8 … int512, uint8 … uint512, int, uint, bool8 … bool64, char8 … char64, float32, float64. Aliases such as bool and byte are ordinary type declarations in Core. Anything else is refused:
error: 'int7' is not a supported intrinsic scalar type
A primitive's representation exists whether or not it is declared; the declaration supplies its API. That is why int8::Max needs import Core::int8; while the type int8 does not — see Imports.
Constants
Associated constants are normally plain source (pub const Max: int8 = 127i8;). The only compiler-supplied ones are Infinity and NaN of float32 and float64, declared in an extend of their own type:
error: intrinsic associated constants support only floating-point Infinity and NaN
Compile-time values
intrinsic #name: Root; declares a value the compiler fills in. The type names which value it is — one of the structs Target, Build, Source, Compiler or Config — and the # name is how code refers to it. Core uses #target, #build, #source, #compiler and #config.
The struct may declare any subset of the fields the compiler supplies for its root, and nothing else, since nothing would fill a field it does not know:
error: field 'wordSize' of 'Target' is not one the compiler supplies for '#target'
help: remove 'wordSize'; the compiler supplies 'os', 'arch', 'abi', 'endian', 'pointerBits', 'dataModel', 'objectFormat', 'triple'
error: 'Widget' is not a value the compiler supplies for '#thing'
help: declare '#thing' with one of 'Target', 'Build', 'Source', 'Compiler', 'Config'
The fields themselves are listed in Context. Field visibility is ordinary: a field the provider leaves private cannot be read by another package, in an expression or in a when condition.
Functions
intrinsic func names a function the compiler implements, so only those it knows are accepted, each with exactly one signature:
| Intrinsic | Signature | Purpose |
|---|---|---|
Assert | (condition: bool, message: char8[..]) | stop the program unless condition holds |
DebugAssert | (condition: bool, message: char8[..]) | the same, removed without debug assertions |
Panic | (message: char8[..]) | stop the program |
#Error | (message: char8[..]) | stop the build — see Diagnostics |
#Warn | (message: char8[..]) | warn during the build |
CheckedAdd, CheckedSub, CheckedMul | (left: uint64, right: uint64, result: *var uint64) -> bool | arithmetic that reports overflow (true on overflow) |
Zeroize | (memory: *var uint8, length: uint64) | a clearing write the optimizer may not remove |
Target.HasFeature | method (self: &Target, feature: TargetFeature) -> bool | #target.HasFeature |
Compiler.HasFeature | method (self: &Compiler, feature: char8[..]) -> bool | #compiler.HasFeature |
Config.Get, Config.Has | methods (self: &Config, name: char8[..]) -> char8[..] / -> bool | #config |
A method intrinsic is declared inside an extend of its struct, which is what gives it its Type.Name key:
extend Target {
pub intrinsic func HasFeature(self: &Target, feature: TargetFeature) -> bool;
}
The diagnostic intrinsics are checked against their signatures, because the compiler emits the call in its own shape:
error: 'Square' is not a supported intrinsic function
help: give the function a body, or declare a foreign function in an 'extern' block
error: intrinsic 'Assert' must be declared as 'func Assert(condition: bool, message: char8[..])'
note: parameter 'condition' has type 'int'
error: 'intrinsic' function cannot have a body
Not intrinsics
Slices, ranges, optionals, fallibles and sums are native types with no declaration at all. intrinsic struct does not exist (error: intrinsic aggregate declarations have been removed; use native slice or range types), and an ordinary struct never gains compiler-owned behaviour from its name. An intrinsic declaration can only bind what the compiler already implements; it cannot add a feature.
See also
- Context — the fields of the compile-time values
- Imports — importing
#names and primitive constants - Primitive types — the constants
Coredeclares for each primitive - API:
Assert,Panic· Learn: Intrinsic, Checked arithmetic, Zeroize