From the output of `-debug-constraints` it looks like the constraint solver hits this issue when it attempts to solve the body as a single expression closure. Adding the explicit return causes the `updatedS[keyPath: kp] = value` line to be solved separately, which works as expected.
More breadcrumbs: when `mutated` is passed a multi-expression closure, the type of `updatedS` is already resolved when we begin to type check the keypath assignment. Then, when we visit the subscript expression, member lookup finds the keypath subscript and generates the appropriate type variable for the key path argument. Later, we visit the `AssignExpr` and generate the type variable for the destination type. Since the argument type variable gets created first, we attempt the binding of the argument to `WritableKeyPath<S, String?>` before the binding of the destination to `String`.
In the single-expression case, we have not yet resolved the type of `updatedS` when we generate constraints for the subscript expression, so member lookup doesn't proceed. Then, the constraint generation for the assign expression gives us the type variable and constraints for the dest type based on the type of `value` (supertypes of `String`). Later, during simplification, we generate the appropriate constraints for the keypath subscript, but now the argument type variable is generated after the destination type of the assign expression. This results in us attempting to bind the dest type to `String` first, which causes the binding of `WritableKeypath<S, String?>` for the argument to fail (since it produces a dest type `String?` instead of `String?`).