vx-lang / vx-lang/Vx

Tensor type audit: T -> (T, dims) -> (T, dims, placement) left earlier assumptions in the tree

Open
#330 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

core-lang refactor
Dominant language
Rust
Stars
14
Forks
2
Avg merge
12h 42m
Merged PRs (30d)
61

Description

The tensor type gained precision in three stages, each in response to something the previous form could not express:

  1. Tensor<T> — the original idea, an element type and nothing else.
  2. Tensor<T, dims> — shape, once it was clear the first form could not describe a tensor precisely enough to check anything about it.
  3. Tensor<T, dims, placement> — where it lives, once placement became the point of the language.

Represented today as Type::Tensor(ElementType, Vec<Expr>, Option<Topology>) (src/syntax/types.rs:200).

The problem is not the destination, which is right. It is that code written against each earlier form is still in the tree, and a value of the later type flowing into a path that assumes the earlier one produces a plausible wrong answer rather than a failure. Three separate defects found in one session all have this shape:

  • #324 — indexing lost the element type and produced f32. The rank-reduction rule reads dims.len() > 1, which is a stage-2 assumption; a stage-1 style Tensor<T> has no dims, so the first index collapsed to a scalar and the second fell through to a default. Every non-f32 element type was affected; f32 hid it because the wrong answer matched.
  • #328let t : Tensor<f16> = Tensor<f16>([2, 2]) binds the annotation verbatim and discards the rank the initializer knew. Preserving it is blocked because method dispatch unifies the whole tensor type, so a shaped receiver stops matching impl Tensor<T> — dispatch is written against stage 1 while bindings would be stage 2.
  • #327 — vectorized slice ops accept f32 only, so the two declaration forms of the same tensor behave differently.

What an audit should settle

Is a dimensionless Tensor<T> a distinct type, or an under-specified one? Today it is both: legal to write, and unable to answer how many indices exhaust it. Either it means "rank unknown" — in which case the rules that index, reduce and dispatch on it need to say what they do with unknown rank — or it should not be spellable and rank should always be inferable. Function parameters (fn f(a : Tensor<f32>)) are the hard case, since there is no initializer to recover rank from.

What does None placement mean? Option<Topology> makes "unplaced" and "host" hard to distinguish, and several paths already default an unknown placement to MemorySpace::CPUDRAM (src/arch.rs:414, :555; src/hir/check/transfer.rs:566, :723). That guess is usually right on a laptop and silently wrong on a machine with a device — which is the case the language exists for, and it feeds capacity admission and transfer cost. See the sentinel-defaults audit issue.

Which parameters participate in which decisions? Concretely: element type and placement should decide assignability; shape should decide capacity and cost; none of them should decide method dispatch (fill applies to a tensor whatever its shape). That last one is exactly what blocks hiraditya/Vx.1#328, and stating the rule explicitly is most of the fix.

Where does the rank-reduction rule belong? t[i] on a rank-2 tensor is a row view; on a rank-1 tensor it is an element; on a rank-unknown tensor it is currently a scalar, which is why hiraditya/Vx.1#324 was reachable at all.

Suggested output

A short written rule per parameter — what it means, what it affects, and what "absent" means — checked against the sites that consume Type::Tensor. The value is less in any single fix than in having a statement to test the code against; each of hiraditya/Vx.1#324, hiraditya/Vx.1#327 and hiraditya/Vx.1#328 was found by accident, and a rule would have made them findable on purpose.

Related: hiraditya/Vx.1#324, hiraditya/Vx.1#327, hiraditya/Vx.1#328, and the sentinel-defaults audit. hiraditya/Vx.1#240 (removing implicit numeric coercion) is the same principle applied to scalars, and worth mirroring: no silent widening between element types either.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Type::Tensor in src/syntax/types.rs:200 and inspect the consumers named in the issue, including src/arch.rs and src/hir/check/transfer.rs. Trace indexing, method dispatch, vectorized slice operations, capacity, and transfer-cost decisions. Done means a short rule for element type, shape, and placement, including what absence means, checked against those sites and the related defects.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.