in the first case ProductName is not a table column, it is an alias. think of it like this:
select case when p.ProductID is null then 'Unknown' else p.ProductName end as ProductName
in the second incorrect query you are trying to do something illegal because you are trying to both select a column from a table and assign to it as if it were an alias you are generating from an expression.
I think your confusion is that you think ProductName is always a column because there is a column with that name in that table, but in this context ProductName is not a column name; it is an alias for the case statement results. so when you try p.ProductName you are telling the SQL engine to select the ProductName column from the p table and then you try to assign a case statement as if it were an alias (which it isn't in the p.ProductName context).
you could just as easily use any name for the case statement since it is an alias. you could do:
select DerivedProductName = case when p.ProductID is null then 'Unknown' else p.ProductName end
does that example make it more clear that you aren't dealing with column names when you use this syntax?