Indeed at some point during development of the fixes (that resolved the real problems for you), we had test failures because sin(1) started to return real(32) rather than real(64).
Perhaps it would be more consistent to choose the “smallest type that fits”, but this will lead to casts in such a sin case. In other words, it trades casts in your situation for casts in another situation. It does not remove the need for casts.
At some point in the development of the branch that fixed real behavior, I had the rule that specifying a non-default type would cause it to be preferred. So that 127:uint(32) + 42 would be a uint(32). This made some sense to me in concept but led to test failures and I wasn’t able to end up at an internally consistent solution. The main complaint I have about it is that the “default size” integer (int(64)) behaves differently than the others. What if you want to request a default-sized integer? You wouldn’t be able to.
In theory, we could have the type system separate an “untyped” or “default” literal from a typed one, so that 1:int(64) and 1 have different types. Even if we got it to work, it would be a pretty big development effort and a breaking change. For one thing, we would need to have a way to write “default size int” as a different type from “int(64)” and use that in various standard libraries. But, at least we could keep the current behavior for foo(42) and sin(1).
Lastly, the easiest solution of all would be to add integer decorators like C has (e.g. 42i64). However that wouldn’t be much use to you if the code you are considering here is generic.
There are several ways to write this that are less ugly, IMO.
First, the parentheses you have are unnecessary
param xp = t + 42:t.type;
You could store the type into a separate variable to simplify if you have multiple such expressions:
type tt = t.type;
param xp = t + 42:tt;
You can specify the type of the param variables (although there are cases where this can result in compilation error; if t is close to the maximum value of its type):
param xp: t.type = t + 42;
Lastly, if you are writing a param-returning function, you can cast on the return (or specify the return type if you are not worried about integer overflow/underflow)
param xp = t + 42;
return xp: t.type;