In reply to Jules:
Allowing a procedural assignment to a wire "appears" to work in some cases. It won't work if there are pullups or any other strengths driving the wire. It won't work when creating EVCD files or any other formats that need to know whether the DUT or TB is actively "driving".
The problem is that the behavior of a wire is defined by a built-in resolution function using the values and strengths of all the drivers(continuous assignments) to a wire. Every time there is a change on one of the drivers, the function is called to produce a resolved value. The function is based on the kind of wire type, wand, wor, tri1, etc.
If you are allowed to make a procedural assignment to a wire, you are bypassing that resolution function to put whatever value you wanted on the wire. If you make a procedural assignment to a wire with the value 'z, the wire goes to 'z. If the resolution of the other drivers would have produced a 0 or 1, you won't see a change on the wire until one of the other drivers has a change. For example
assign (weak1,weak0) w = 1;
// time 0 w is 1
#1 w = 0; // w goes to 0
#1 w = 'z; // w goes to z
#1 // w stays at z, never goes back to 1