Got some confirmation from the PowerShell team on this. This seems to be a bug in the XML adapter. If you look at the object that foo2 pops in the debugger, this is PSObject. If you do not use the return keyword and instead simply output the string "foo2", then the function returns a string object.
XML , PSObject . , PSObject $xml.node, . , , psobject ( [string]):
$xml = [xml] '<node>foo</node>'
function foo2 { return "foo2" }
$xml.node = (foo2).psobject.baseobject
$xml
node
----
foo2