I suspect it's expected behaviour, as paths are actually trickier that you expect, so doing it "right" takes being very clear about what you're trying to do.
To work around it, you could try recreating the child PathBuf by taking the components and skipping the first element (the CurDir).
let child = child.components().skip(1).collect::<PathBuf>();
or maybe use .filter(|c| !matches!(c, Component::CurDir)) if you're not sure if your child actually starts with ./. though then you check all the other parts unnecessarily, so maybe a check to see if the first element in components() is Component::CurDir, then use the skip if so.
The thing is, these two path suffixes do not mean the same thing.
The . in the first path is part of an absolute path. It's known that /foo/goo/. is unconditionally the same as /foo/goo. On the other hand, the second path is relative as it begins with the current directory – whatever it may be (eg. /bar/baz).
So no, the second path is not a suffix of the first obe, and the observed behavior is correct.
Keep in mind that will also fail for non-existent paths and will follow symlinks: std::env::current_dir()?.join(child) is a more conservative (and faster) equivalent, but it depends on what you're after.