For example, let's say my project depends on two libraries; A and B. Both depend on library C.
If A depends on C version ^ 1.0.0, and B depends on C version ^ 1.1.0, and 1.2.0 is the latest version of C, then both A and B will end up with C 1.2.0.
If A depends on C = 1.0.0, and B depends on C version = 1.1.0, then you'll get two copies of C.
B is expecting C = 2.0.0. A is expecting C = 1.0.0. A makes a call to B, which it passes to C. Does A know that B now expects to be called differently, since C is also significantly different now? According to the above requirements, no version of the deps exist that could allow the app to execute correctly, even though it will technically build fine.
The way to resolve this would be to say A requires C < 2.0.0, and simply fail to build until someone fixes A. But you probably won't even know about this conflict until someone tests the app with a specific feature of A that conflicts with C >= 2.0.0, the build fails, someone figures out the conflict, and updates the requirements.
But you can only know this, and add this requirement, once you have found the conflict. Thus code in the present, even with dependency requirements, may be indeterminate in the future. (Unless you walk back through all calls in the code to find calls between multiple dependencies that eventually land on conflicts... but I don't think that is possible in Turing-complete languages)
If you pinned the version in each function call in each part of the code, you could have the compiler or interpreter walk back through dependent code, identify mismatches, retrieve a compatible dependency, and continue execution. Or at the very least throw warnings all over the place when code is running using dependencies it wasn't written for.