From my understanding, dependent types can
model linearity, but you'd need to use that model type system rather than the 'native' type system (similar to how, for example, Bash can
model OOP (e.g. using a mixture of naming conventions, associative arrays, eval, etc.), but isn't
natively OOP). If we go down that route, we're essentially building our own programming language, which is inherently incompatible with the dependently-typed language we've used to create it (in particular: functions in the underlying language cannot be used in our linear-types language, since they have no linearity constraints).
A common example is a file handle: I can prove that the 'close' function will produce a closed handle, e.g.
close : Handle Open -> Handle Closed
I can prove that those handles point to the same file:
close : (f: Filename) -> Handle f Open -> Handle f Closed
I can prove arbitrary relationships between the input values and the output value. Yet nothing I do restrict the
structure of a term, like how many times a variable is used, to prevent e.g.
foo h = snd (close h, readLine h)
For that sort of control, we need to build the ability to track things into the term language itself; either by adding linear types (or equivalent) to the language, or building a new incompatible language on top (as I mentioned above).