To ensure that the strings are not truncated incorrectly, we need to make sure that at least one value involved in the string operation is of MAX data type so that the result is also a MAX value.
It comes down to the return type of the function. The MSDN documentation specifies the return type as:
Returns the same type as string_expression.
Remember that varchar(max) and varbinary(max) are BLOBs so are different types to varchar(n) and varbinary(n). You wouldn't consider char(n) the same type as varchar(n) would you? :)
Moreover, this functionality isn't particular to the REPLICATE function. Consider the following:
DECLARE @a varchar(5000);
SELECT @a = REPLICATE('a', 5000);
SELECT LEN(@a), LEN(@a + @a);
Would you be surprised to learn that LEN(@a + @a) is 8,000? And it's not the LEN function which is truncating the input! @a + @a returns a string of just 8,000 characters, not 10,000. If you don't believe it, try creating a new table and allow sql to assign the appropriate type for @a+@a:
DECLARE @a varchar(5000) = REPLICATE('a', 5000);
SELECT @a + @a AS testType INTO testblob;
-- check the type of the field created in object explorer or with the following:
SELECT LEN(testType), DATALENGTH(testType) FROM testblob;
DROP TABLE testblob;
If that still surprises you, how about:
DECLARE @i int = 2147483647; -- maximum value of signed int
Msg 8115, Level 16, State 2, Line 2
Arithmetic overflow error converting expression to data type int.
I hope this has hammered the point home. If it's left you more confused, it's probably a good thing as it's pointed out that you need to review your sql types :D