Repository: pydantic/pydantic

Issue:
list is not equivalent to typing.List under combination of generics and futures
### Initial Checks

- [X] I have searched GitHub for a duplicate issue and I'm sure this is something new
- [X] I have searched Google & StackOverflow for a solution and couldn't find anything
- [X] I have read and followed [the docs](https://docs.pydantic.dev) and still think this is a bug
- [X] I am confident that the issue is with pydantic (not my code, or another library in the ecosystem like [FastAPI](https://fastapi.tiangolo.com) or [mypy](https://mypy.readthedocs.io/en/stable))


### Description

This is a strange one - under the below conditions, exchanging `typing.List` for the more modern `list` produces the below error. I can't reproduce in a simpler example than this - it looks to me like a bug in pydantic:

```
Traceback (most recent call last):
  File "pydantic/validators.py", line 751, in pydantic.validators.find_validators
TypeError: issubclass() arg 1 must be a class

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "{path_to_test}/test.py", line 11, in <module>
    outer = Outer["Inner"]
  File "{path_to_pydantic}/pydantic/generics.py", line 163, in __class_getitem__
    _prepare_model_fields(created_model, fields, instance_type_hints, typevars_map)
  File "{path_to_pydantic}/pydantic/generics.py", line 389, in _prepare_model_fields
    field.prepare()
  File "pydantic/fields.py", line 552, in pydantic.fields.ModelField.prepare
  File "pydantic/fields.py", line 758, in pydantic.fields.ModelField._type_analysis
  File "pydantic/fields.py", line 808, in pydantic.fields.ModelField._create_sub_type
  File "pydantic/fields.py", line 436, in pydantic.fields.ModelField.__init__
  File "pydantic/fields.py", line 557, in pydantic.fields.ModelField.prepare
  File "pydantic/fields.py", line 831, in pydantic.fields.ModelField.populate_validators
  File "pydantic/validators.py", line 760, in find_validators
RuntimeError: error checking inheritance of 'Inner' (type: str)
```

I've also displayed the minimal example below - thanks!

### Example Code

```Python
from typing import Generic, List, TypeVar

from pydantic import BaseModel
from pydantic.generics import GenericModel

ChangingType = TypeVar("ChangingType")

class Outer(GenericModel, Generic[ChangingType]):
    fields_: list[ChangingType] # Swapping list -> List on this line fixes the bug

outer = Outer["Inner"]
class Inner(BaseModel):
    new: list[outer]

outer.update_forward_refs()
Inner.update_forward_refs()

out = Inner.parse_obj({"new": [{"fields_": []}]})

print(out)
```


### Python, Pydantic & OS Version

```Text
pydantic version: 1.10.9
pydantic compiled: True
install path: /{package location}/.venv/lib64/python3.10/site-packages/pydantic
python version: 3.10.10 (main, Feb  8 2023, 00:00:00) [GCC 12.2.1 20221121 (Red Hat 12.2.1-4)]
platform: Linux-5.10.16.3-microsoft-standard-WSL2-x86_64-with-glibc2.35
optional deps. installed: ['typing-extensions']
```


### Affected Components

- [ ] [Compatibility between releases](https://docs.pydantic.dev/changelog/)
- [ ] [Data validation/parsing](https://docs.pydantic.dev/usage/models/#basic-model-usage)
- [ ] [Data serialization](https://docs.pydantic.dev/usage/exporting_models/) - `.dict()` and `.json()`
- [ ] [JSON Schema](https://docs.pydantic.dev/usage/schema/)
- [ ] [Dataclasses](https://docs.pydantic.dev/usage/dataclasses/)
- [ ] [Model Config](https://docs.pydantic.dev/usage/model_config/)
- [x] [Field Types](https://docs.pydantic.dev/usage/types/) - adding or changing a particular data type
- [ ] [Function validation decorator](https://docs.pydantic.dev/usage/validation_decorator/)
- [X] [Generic Models](https://docs.pydantic.dev/usage/models/#generic-models)
- [ ] [Other Model behaviour](https://docs.pydantic.dev/usage/models/) - `construct()`, pickling, private attributes, ORM mode
- [ ] [Plugins](https://docs.pydantic.dev/) and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.


Discussion:
I've found a couple more illustrations - one is a simplified version of the original minimal, and second illustrates the same bug with Dict -> dict

List version
```py
from typing import Generic, List, TypeVar

from pydantic import BaseModel
from pydantic.generics import GenericModel

ChangingType = TypeVar("ChangingType")

class Outer(GenericModel, Generic[ChangingType]):
    test: list[ChangingType]

OuterNew = Outer["Inner"]
class Inner(BaseModel):
    new: int

OuterNew.update_forward_refs()
out = OuterNew.parse_obj({"test": [{"new": 1}]})

print(out)
```

Dict version
```py
from typing import Dict, Generic, List, TypeVar

from pydantic import BaseModel
from pydantic.generics import GenericModel

ChangingType = TypeVar("ChangingType")

class Outer(GenericModel, Generic[ChangingType]):
    test: dict[str, ChangingType]

OuterNew = Outer["Inner"]
class Inner(BaseModel):
    new: int

OuterNew.update_forward_refs()
out = OuterNew.parse_obj({"test": {"t": {"new": 1}}})

print(out)
```
https://github.com/pydantic/pydantic/blob/1.10.X-fixes/pydantic/typing.py#L218

Think this is relevent - just testing

Update: Tested this function - seems to be working ok
Ok think I might have it: https://github.com/pydantic/pydantic/blob/1.10.X-fixes/pydantic/generics.py#L293

In this line the origins are correctly found as List or list, but the difference is that...

List['test'] -> List[ForwardRef('test')]
While
list['test'] -> list['test'], when it should be list[ForwardRef('test')] - which as it turns out are not equivalent. There needs to be something in this replace_args function that converts strings to ForwardRefs


Resolving patch:
diff --git a/pydantic/generics.py b/pydantic/generics.py
--- a/pydantic/generics.py
+++ b/pydantic/generics.py
@@ -6,6 +6,7 @@
     Any,
     ClassVar,
     Dict,
+    ForwardRef,
     Generic,
     Iterator,
     List,
@@ -19,7 +20,7 @@
 )
 from weakref import WeakKeyDictionary, WeakValueDictionary
 
-from typing_extensions import Annotated
+from typing_extensions import Annotated, Literal as ExtLiteral
 
 from .class_validators import gather_all_validators
 from .fields import DeferredType
@@ -30,6 +31,8 @@
 
 if sys.version_info >= (3, 10):
     from typing import _UnionGenericAlias
+if sys.version_info >= (3, 8):
+    from typing import Literal
 
 GenericModelT = TypeVar('GenericModelT', bound='GenericModel')
 TypeVarType = Any  # since mypy doesn't allow the use of TypeVar as a type
@@ -267,6 +270,8 @@ def replace_types(type_: Any, type_map: Mapping[Any, Any]) -> Any:
         annotated_type, *annotations = type_args
         return Annotated[replace_types(annotated_type, type_map), tuple(annotations)]
 
+    if (origin_type is ExtLiteral) or (sys.version_info >= (3, 8) and origin_type is Literal):
+        return type_map.get(type_, type_)
     # Having type args is a good indicator that this is a typing module
     # class instantiation or a generic alias of some sort.
     if type_args:
@@ -317,7 +322,12 @@ def replace_types(type_: Any, type_map: Mapping[Any, Any]) -> Any:
 
     # If all else fails, we try to resolve the type directly and otherwise just
     # return the input with no modifications.
-    return type_map.get(type_, type_)
+    new_type = type_map.get(type_, type_)
+    # Convert string to ForwardRef
+    if isinstance(new_type, str):
+        return ForwardRef(new_type)
+    else:
+        return new_type
 
 
 def check_parameters_count(cls: Type[GenericModel], parameters: Tuple[Any, ...]) -> None:


Test patch: