Repository: facebookresearch/hydra

Issue:
[Bug] Defaults Populated Structured Config
# 🐛 Bug

I am trying to create a top level structured configuration which is used to check my config.yaml.  At the moment, I cannot get the defaults to be populated and correctly working will null initializers. I created a sample of this here: https://github.com/anthonytec2/hydra/commit/38b94c57928f50f9f5ec196346dd445b5f96094c. Thing works when assigning defaults to be field(default_factory=lambda: defaults), but fails when assigned to MISSING. 

## To reproduce

** Stack trace/error message **
```
Cannot iterate a missing ListConfig
	full_key: defaults
	reference_type=List[Any]
	object_type=list
```

## System information
- **Hydra Version** :   1.0.0rc2
- **Python version** : 3.7.7
- **Virtual environment type and version** : 
- **Operating system** : Ubuntu 18.04




Discussion:
Please create a zip file with a minimal rero. (app.py, and the relevant yaml config file).
[struct.zip](https://github.com/facebookresearch/hydra/files/4922498/struct.zip)


Resolving patch:
diff --git a/hydra/_internal/config_loader_impl.py b/hydra/_internal/config_loader_impl.py
--- a/hydra/_internal/config_loader_impl.py
+++ b/hydra/_internal/config_loader_impl.py
@@ -521,6 +521,26 @@ def _raise_parse_override_error(override: Optional[str]) -> None:
         )
         raise HydraException(msg)
 
+    def _record_loading(
+        self,
+        name: str,
+        path: Optional[str],
+        provider: Optional[str],
+        schema_provider: Optional[str],
+        record_load: bool,
+    ) -> Optional[LoadTrace]:
+        trace = LoadTrace(
+            filename=name,
+            path=path,
+            provider=provider,
+            schema_provider=schema_provider,
+        )
+
+        if record_load:
+            self.all_config_checked.append(trace)
+
+        return trace
+
     @staticmethod
     def _combine_default_lists(
         primary: List[DefaultElement], merged_list: List[DefaultElement]
@@ -553,24 +573,6 @@ def _load_config_impl(
         :return: the loaded config or None if it was not found
         """
 
-        def record_loading(
-            name: str,
-            path: Optional[str],
-            provider: Optional[str],
-            schema_provider: Optional[str],
-        ) -> Optional[LoadTrace]:
-            trace = LoadTrace(
-                filename=name,
-                path=path,
-                provider=provider,
-                schema_provider=schema_provider,
-            )
-
-            if record_load:
-                self.all_config_checked.append(trace)
-
-            return trace
-
         ret = self.repository.load_config(
             config_path=input_file,
             is_primary_config=is_primary_config,
@@ -596,11 +598,12 @@ def record_loading(
                     assert isinstance(merged, DictConfig)
                     return (
                         merged,
-                        record_loading(
+                        self._record_loading(
                             name=input_file,
                             path=ret.path,
                             provider=ret.provider,
                             schema_provider=schema.provider,
+                            record_load=record_load,
                         ),
                     )
 
@@ -610,18 +613,23 @@ def record_loading(
 
             return (
                 ret.config,
-                record_loading(
+                self._record_loading(
                     name=input_file,
                     path=ret.path,
                     provider=ret.provider,
                     schema_provider=None,
+                    record_load=record_load,
                 ),
             )
         else:
             return (
                 None,
-                record_loading(
-                    name=input_file, path=None, provider=None, schema_provider=None
+                self._record_loading(
+                    name=input_file,
+                    path=None,
+                    provider=None,
+                    schema_provider=None,
+                    record_load=record_load,
                 ),
             )
 
@@ -863,9 +871,11 @@ def get_overrides_dirname(
 def _recursive_unset_readonly(cfg: Container) -> None:
     if isinstance(cfg, DictConfig):
         OmegaConf.set_readonly(cfg, None)
-        for k, v in cfg.items_ex(resolve=False):
-            _recursive_unset_readonly(v)
+        if not cfg._is_missing():
+            for k, v in cfg.items_ex(resolve=False):
+                _recursive_unset_readonly(v)
     elif isinstance(cfg, ListConfig):
         OmegaConf.set_readonly(cfg, None)
-        for item in cfg:
-            _recursive_unset_readonly(item)
+        if not cfg._is_missing():
+            for item in cfg:
+                _recursive_unset_readonly(item)


Test patch:
diff --git a/tests/test_apps/defaults_in_schema_missing/conf/config.yaml b/tests/test_apps/defaults_in_schema_missing/conf/config.yaml
new file mode 100644
--- /dev/null
+++ b/tests/test_apps/defaults_in_schema_missing/conf/config.yaml
@@ -0,0 +1,2 @@
+defaults:
+  - db: mysql
diff --git a/tests/test_apps/defaults_in_schema_missing/conf/db/mysql.yaml b/tests/test_apps/defaults_in_schema_missing/conf/db/mysql.yaml
new file mode 100644
--- /dev/null
+++ b/tests/test_apps/defaults_in_schema_missing/conf/db/mysql.yaml
@@ -0,0 +1,3 @@
+# @package _group_
+user: omry
+password: secret
diff --git a/tests/test_apps/defaults_in_schema_missing/my_app.py b/tests/test_apps/defaults_in_schema_missing/my_app.py
new file mode 100644
--- /dev/null
+++ b/tests/test_apps/defaults_in_schema_missing/my_app.py
@@ -0,0 +1,43 @@
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
+from dataclasses import dataclass
+from typing import Any, List
+
+from omegaconf import MISSING, DictConfig
+
+import hydra
+from hydra.core.config_store import ConfigStore
+
+
+@dataclass
+class DBConfig:
+    driver: str = MISSING
+    host: str = "localhost"
+    port: int = MISSING
+
+
+@dataclass
+class MySQLConfig(DBConfig):
+    driver: str = "mysql"
+    port: int = 3306
+    user: str = MISSING
+    password: str = MISSING
+
+
+@dataclass
+class Config:
+    defaults: List[Any] = MISSING
+    db: DBConfig = MISSING
+
+
+cs = ConfigStore.instance()
+cs.store(group="db", name="mysql", node=MySQLConfig, provider="main")
+cs.store(name="config", node=Config, provider="main")
+
+
+@hydra.main(config_path="conf", config_name="config")
+def my_app(cfg: DictConfig) -> None:
+    print(cfg.pretty())
+
+
+if __name__ == "__main__":
+    my_app()