Repository: pytorch
Issue: Torch.fx tracing bug with dictionary.update calls on input
Labels: triaged,module: fx,fx

### 🐛 Describe the bug

## Bug Description
Torch.fx incorrectly traces models that call `update` on their input dictionary. The incorrect model structure results in most nodes being removed if a call to `model.graph.eliminate_dead_code()` is made.  I believe from similar examples that instead of returning a traced model, this should error out.
## Minimal Reproducible Example
```
from torch import nn
import torch.nn.functional as F
from torch import fx

class TestModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10,10)
        self.fc2 = nn.Linear(10,10)
    def forward(self, input_dict):
        out = {"out1": F.relu(self.fc1(input_dict['in']))}
        input_dict.update(out)
        out = {"out2": F.relu(self.fc2(input_dict['out1']))}
        input_dict.update(out)
        return input_dict['out2']

model = TestModel()
model = fx.symbolic_trace(model)
model.graph.print_tabular()
```
which results in:
```
opcode         name        target                             args                            kwargs
-------------  ----------  ---------------------------------  ------------------------------  ------------------
placeholder    input_dict  input_dict                         ()                              {}
call_function  getitem     <built-in function getitem>        (input_dict, 'in')              {}
call_module    fc1         fc1                                (getitem,)                      {}
call_function  relu        <function relu at 0x7f70b9e11d90>  (fc1,)                          {'inplace': False}
call_method    update      update                             (input_dict, {'out1': relu})    {}
call_function  getitem_1   <built-in function getitem>        (input_dict, 'out1')            {}
call_module    fc2         fc2                                (getitem_1,)                    {}
call_function  relu_1      <function relu at 0x7f70b9e11d90>  (fc2,)                          {'inplace': False}
call_method    update_1    update                             (input_dict, {'out2': relu_1})  {}
call_function  getitem_2   <built-in function getitem>        (input_dict, 'out2')            {}
output         output      output                             (getitem_2,)                    {}
```

#### Visualization
![Screen Shot 2022-08-30 at 4 40 53 PM](https://user-images.githubusercontent.com/16086901/187562339-a5cdde2c-444e-4b75-953e-4ed49b487828.png)

###  Result of calling `eliminate_dead_code`
```
from torch import nn
import torch.nn.functional as F
from torch import fx

class TestModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10,10)
        self.fc2 = nn.Linear(10,10)
    def forward(self, input_dict):
        out = {"out1": F.relu(self.fc1(input_dict['in']))}
        input_dict.update(out)
        out = {"out2": F.relu(self.fc2(input_dict['out1']))}
        input_dict.update(out)
        return input_dict['out2']

model = TestModel()
model = fx.symbolic_trace(model)
model.graph.eliminate_dead_code()
model.graph.print_tabular()
```
This results in:
```
opcode         name        target                       args                  kwargs
-------------  ----------  ---------------------------  --------------------  --------
placeholder    input_dict  input_dict                   ()                    {}
call_function  getitem_2   <built-in function getitem>  (input_dict, 'out2')  {}
output         output      output                       (getitem_2,)          {}
```
### Similar Example (without using update)
If we instead directly update the input dictionary, instead of using `update` calls, the trace will fail:
```
from torch import nn
import torch.nn.functional as F
from torch import fx

class TestModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10,10)
    def forward(self, input_dict):
        input_dict['out1'] = F.relu(self.fc1(input_dict['in']))
        return input_dict['out1']

model = TestModel()
try:
    model = fx.symbolic_trace(model)
except TypeError as e:
    print(e)
```
We get the error:
```
'Proxy' object does not support item assignment
```
For this reason, I believe erroring out when the same behaviour is replicated by using `update` calls instead is the correct approach.

### Versions


Collecting environment information...
PyTorch version: 1.11.0
Is debug build: False
CUDA used to build PyTorch: None
ROCM used to build PyTorch: N/A

OS: macOS 12.4 (x86_64)
GCC version: Could not collect
Clang version: Could not collect
CMake version: version 3.21.1
Libc version: N/A

Python version: 3.9.6 (default, Jun 29 2021, 05:25:02)  [Clang 12.0.5 (clang-1205.0.22.9)] (64-bit runtime)
Python platform: macOS-12.4-x86_64-i386-64bit
Is CUDA available: False
CUDA runtime version: No CUDA
GPU models and configuration: No CUDA
Nvidia driver version: No CUDA
cuDNN version: No CUDA
HIP runtime version: N/A
MIOpen runtime version: N/A
Is XNNPACK available: True

Versions of relevant libraries:
[pip3] numpy==1.21.1
[pip3] torch==1.11.0
[pip3] torchvision==0.12.0
[conda] Could not collect

cc @ezyang @SherlockNoMad @soumith