E6025
E6025 — A placement naming a location the machine does not have: a memory space no declared topology holds, written either as the space or as the device that would hold it. The derivation between the two spellings has a like-named fallback, so an undeclared name resolves to a space that exists only in the placement that mentions it.
What the compiler reports
E6025
`Memory::Nowhere` in function 'as_a_parameter'
`Topology::Nowhere` in function 'as_a_device'
`Memory::Nowhere` in function 'as_a_return'
`Memory::Nowhere` in field 'absent' of struct 'Holder'
`Memory::Nowhere` in variable 'annotated'
The fragments the test suite holds the compiler to. An ellipsis marks text the test does not constrain; the emitted message also carries a source location.
A program that triggers it
// A placement has to name a space some declared topology holds.
//
// A placement carries a device and a space together and derives whichever half the source did not
// write. Both derivations fall back to the like-named other half when the declarations cannot
// answer: `Memory::Nowhere` derives `Topology::Nowhere`, and `Topology::Nowhere` derives
// `Memory::Nowhere`. The pair that comes out is internally consistent, compares equal to itself,
// and describes a machine nobody has. That is why writing a name nothing declares used to compile.
//
// Writing the device and writing the space are meant to be two ways of saying one thing, so they
// have to be refused alike -- refusing one and accepting the other would make the choice of
// spelling matter. Each is checked on the half the source wrote: a device names a place when the
// compilation declares it, a space when some declared topology holds it.
//
// Only the written half, because the derived one is not filled in yet. The derivation runs in name
// resolution, and a program that fails the type checker never gets that far, so a placement here
// still carries what the parser guessed -- for `Topology::Island` that is the like-named
// `Memory::Island` rather than the `memory:` its declaration gives. Reading the derived half would
// refuse `holds_by_device` below, which is correct code.
//
// Held is wider than owned: a space named only in a topology's `visible:` list has no single
// owning device and is still a real place, so `Vault` below is accepted through `Island`.
//
// All four positions a placed type is spellable in are covered, because each is reached by
// different code: parameters and return types come from the function table, fields from the struct
// table, and a `let` annotation from the statement walk, which no declaration table sees.
//
// The fail tier matches against the debug dump of the diagnostics rather than the rendered console
// output, so a code and its message are on separate lines and cannot be matched by one pattern.
// The code is matched bare: the dump writes `E6025,` and the console `Error[E6025]:`, and the RUN
// line above sees the second of those.
//
// Nothing declared is refused: five diagnostics, not six or seven. Counted on a pass of its own,
// because a count directive after the group above would ask for five more beyond the five matched.
// COUNT-COUNT-5: names no location
// COUNT-NOT: names no location
Memory Vault {
capacity: 8 GB, bandwidth: 1 TB/s
}
Topology Island {
memory: Memory::Vault,
visible: [ Memory::Vault ],
transfer Memory::CPU_DRAM -> Memory::Vault : 100,
}
struct Holder {
absent : Tensor<f32, [ 4, 4 ], Memory::Nowhere>,
present : Tensor<f32, [ 4, 4 ], Memory::Vault>,
}
fn as_a_parameter(t : Tensor<f32, [ 4, 4 ], Memory::Nowhere>) -> void {
}
fn as_a_device(t : Tensor<f32, [ 4, 4 ], Topology::Nowhere>) -> void {
}
fn as_a_return() -> Tensor<f32, [ 4, 4 ], Memory::Nowhere> {
return Tensor<f32, [ 4, 4 ], Memory::Nowhere>::uninit();
}
// A declared space, held by a declared topology, in every position the ones above are refused in.
fn declared_is_fine(t : Tensor<f32, [ 4, 4 ], Memory::Vault>) -> Tensor<f32, [ 4, 4 ], Memory::Vault> {
return Tensor<f32, [ 4, 4 ], Memory::Vault>::uninit();
}
// A built-in space needs no declaration: its owning device is stated in the compiler.
fn builtin_is_fine(t : Tensor<f32, [ 4, 4 ], Memory::GPU_HBM>) -> void {
}
// The same place written as the device that holds it. `Island`'s memory is `Vault`, not the
// like-named `Memory::Island`, so this is the case that fails if the check reads the derived half.
fn holds_by_device(t : Tensor<f32, [ 4, 4 ], Topology::Island>) -> void {
}
fn main() -> i32 {
let annotated : Tensor<f32, [ 2, 2 ], Memory::Nowhere> = Tensor<f32, [ 2, 2 ], Memory::Nowhere>::uninit();
return 0;
}
From tests/middle_end/fail/placement_names_no_place.vx, which asserts this diagnostic on every commit.
Related
Topologies and memoryThe chapter covering the rule this code enforces.
All diagnosticsEvery code the compiler can emit, grouped by stage.
E6024A proof obligation could not be discharged because no SMT solver was available. Fails the compilation by default: an undischarged obligation is not a proved one, and treating the two alike is what let a missing z3 certify every seam in silence (Vx#374). Set
VX_ALLOW_UNVERIFIED=1 to downgrade this to W1031 and compile anyway.
E6026A tensor whose element type the target hardware cannot represent, placed on it anyway. The machine model states what a device has (dtypes: [f32, f16, ...]); this is the check that a placement stays inside it. An H100 has no fp4, so an fp4 tensor placed on one asks for silicon that is not there — and the placement is in the type, so the question is answerable here rather than at a kernel launch on the machine that lacks the type. Only fires against a topology that declares dtypes:. An undeclared machine constrains nothing, which is what keeps every machine file written before the field kept working.