<!--- Verify first that your issue is not already reported on GitHub -->
<!--- Also test if the latest release and devel branch are affected too -->
<!--- Complete *all* sections as described, this form is processed automatically -->

##### SUMMARY
I've spent the better part of a working day troubleshooting this specific issue, and I don't think this issue is documented or already reported. I have a dictionary, which *sometimes* contains a list of dicts to be looped on, depending on what a key in the inside dict is set to.

So obviously I want to skip the task entirely when that list isn't present, and that is not a problem. But when combined with a check for a key value on item inside the loop, the when condition fails complaining about the list being undefined. Which is hugely annoying as I was checking explicitly for that in the first condition of my when statement.

This is part of a larger playbook which I cannot share, but I've managed to reproduce it with a small test case. I will paste two small playbooks, one that works and one that doesn't. (But in my opinion it should.)

##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
ansible

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes -->
```
ansible-playbook 2.8.0a1.post0
  config file = /Users/jh/git/ansible_cisco/ansible.cfg
  configured module search path = [u'/Users/jh/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/jh/git/ansible_cisco/lib/python2.7/site-packages/ansible
  executable location = ./bin/ansible-playbook
  python version = 2.7.10 (default, Feb 22 2019, 21:55:15) [GCC 4.2.1 Compatible Apple LLVM 10.0.1 (clang-1001.0.37.14)]
```

##### CONFIGURATION
<!--- Paste verbatim output from "ansible-config dump --only-changed" between quotes -->
```
DEFAULT_STDOUT_CALLBACK(/Users/jh/git/ansible_cisco/ansible.cfg) = skippy
DEFAULT_TIMEOUT(/Users/jh/git/ansible_cisco/ansible.cfg) = 300
HOST_KEY_CHECKING(/Users/jh/git/ansible_cisco/ansible.cfg) = False
INTERPRETER_PYTHON(/Users/jh/git/ansible_cisco/ansible.cfg) = ./bin/python
PARAMIKO_LOOK_FOR_KEYS(/Users/jh/git/ansible_cisco/ansible.cfg) = False
PERSISTENT_COMMAND_TIMEOUT(/Users/jh/git/ansible_cisco/ansible.cfg) = 300
PERSISTENT_CONNECT_TIMEOUT(/Users/jh/git/ansible_cisco/ansible.cfg) = 300
RETRY_FILES_ENABLED(/Users/jh/git/ansible_cisco/ansible.cfg) = False
TRANSFORM_INVALID_GROUP_CHARS(/Users/jh/git/ansible_cisco/ansible.cfg) = ignore
```

##### OS / ENVIRONMENT
<!--- Provide all relevant information below, e.g. target OS versions, network device firmware, etc. -->
Running MacOS X Mojave and use a python virtualenv for the sole purpose of having stable versions of everything in this specific repository. None of this should matter though as this seems to be a purely ansible core thing.


##### STEPS TO REPRODUCE
<!--- Describe exactly how to reproduce the problem, using a minimal test-case -->

This playbook will fail with an error about mylist2 not being defined, despite the when statement explicitly checking for that. Remove the and item.test = test part from the when statement and it will work correctly.
```
---
- name: test ansible when defined
  hosts: localhost
  become: no
  gather_facts: no
  vars:
    mydict:
      var1: "val1"
      var2: "val2"
      mylist1:
        - test1
        - test2
  tasks:
    - debug:
        var: mydict

    - debug:
        msg: "This shouldn't be printed."
      with_items: "{{mydict.mylist2}}"
      when: mydict.mylist2 is defined and item.test = 'test'
```

This version, with the parts of the when statement on different lines works:
```
---
- name: test ansible when defined
  hosts: localhost
  become: no
  gather_facts: no
  vars:
    mydict:
      var1: "val1"
      var2: "val2"
      mylist1:
        - test1
        - test2
  tasks:
    - debug:
        var: mydict

    - debug:
        msg: "This shouldn't be printed."
      with_items: "{{mydict.mylist2}}"
      when:
        - mydict.mylist2 is defined
        - item.test = 'test'
```

<!--- HINT: You can paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- Describe what you expected to happen when running the steps above -->

I would expect both cases to work, and just skip the second task.

```
./bin/ansible-playbook works.yml
 [WARNING]: No inventory was parsed, only implicit localhost is available

 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not
match 'all'


PLAY [test ansible when defined] *************************************************************************************

TASK [debug] *********************************************************************************************************
ok: [localhost] => {
    "mydict": {
        "mylist1": [
            "test1",
            "test2"
        ],
        "var1": "val1",
        "var2": "val2"
    }
}

TASK [debug] *********************************************************************************************************

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
```

##### ACTUAL RESULTS
<!--- Describe what actually happened. If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes -->
```
./bin/ansible-playbook fails.yml
 [WARNING]: No inventory was parsed, only implicit localhost is available

 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not
match 'all'


PLAY [test ansible when defined] *************************************************************************************

TASK [debug] *********************************************************************************************************
ok: [localhost] => {
    "mydict": {
        "mylist1": [
            "test1",
            "test2"
        ],
        "var1": "val1",
        "var2": "val2"
    }
}

TASK [debug] *********************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "'dict object' has no attribute 'mylist2'"}

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
```
raise AnsibleError("the connection plugin '%s' was not found" % conn_type)
        
        if cvars.get('ansible_become', self._task.become):
            become_plugin = self._get_become(cvars.get('ansible_become_method', self._task.become_method))
            try:
                connection.set_become_plugin(become_plugin)
            except AttributeError:
                
                pass
            if getattr(connection.become, 'require_tty', False) and not getattr(connection, 'has_tty', False):
                raise AnsibleError(
                    "The '%s' connection does not provide a TTY which is required for the selected "
                    "become plugin: %s." % (conn_type, become_plugin.name)
                )
            
            
            
            self._play_context.set_become_plugin(become_plugin.name)
        
        self._play_context.set_attributes_from_plugin(connection)
        if any(((connection.supports_persistence and C.USE_PERSISTENT_CONNECTIONS), connection.force_persistence)):
            self._play_context.timeout = connection.get_option('persistent_command_timeout')
            display.vvvv('attempting to start connection', host=self._play_context.remote_addr)
            display.vvvv('using connection plugin %s' % connection.transport, host=self._play_context.remote_addr)
            options = self._get_persistent_connection_options(connection, variables, templar)
            socket_path = start_connection(self._play_context, options, self._task._uuid)
            display.vvvv('local domain socket path is %s' % socket_path, host=self._play_context.remote_addr)
            setattr(connection, '_socket_path', socket_path)
        return connection
    def _get_persistent_connection_options(self, connection, variables, templar):