normalization should not affect the resolved path
# let x = Cons (Link(name_exn "foo", Item Dot), Item Dotdot);;
val x : (rel, dir) t = Cons (Link ("foo", Item Dot), Item Dotdot)
# normalize x;;
- : (rel, dir) t = Item Dot
Path x semantically (i.e. resolve and then normalize) points to Dotdot, but normalize returns Dot. The reason is our implementation of normalize does
| Link _, Item Dotdot -> Item Dot
which moves up through the link. This definition agrees with my shell's behavior (where the prompt is configured to show the current working directory):
~/phat-test $ ln -s . a
~/phat-test $ ls -al
lrwx------ 1 ashish staff 1B Dec 11 11:08 a -> .
~/phat-test $ cd a
~/phat-test/a $ cd ..
~/phat-test $
The shell treats a as a regular directory. Doing a cd moves you to it, with PWD showing you one level lower in your directory tree, even though a points to the current directory. This isn't necessarily wrong, but doesn't align with our goal for normalize, which is that normalization shouldn't change a path's semantics. The shell could reasonably have implemented an alternative, that cding to a link takes you to its target, but there is an attempt here at letting users leave the link unresolved. Presumably this is more intuitive in some cases.
Originally reported by @pveber.
Decision: a normalized path can also include a Link followed immediately by one or more Dotdots.