Repository: pydantic/pydantic

Issue:
defining a validator causes mypy: maximum semantic analysis iteration count reached
### 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

Hi, I'm getting the mypy `INTERNAL ERROR: maximum semantic analysis iteration count reached` error when defining a validator in a model via a helper function. Note that declaring the type of the validator makes mypy not crash anymore (see example). Also the issue occurs only with `pydantic.mypy` plugin.

```
mypy tests/test_validators2.py
Deferral trace:
    tests.test_validators2:13
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
    tests.test_validators2:11
tests/test_validators2.py: error: INTERNAL ERROR: maximum semantic analysis iteration count reached
Found 1 error in 1 file (errors prevented further checking)
```

### Example Code

```Python
import pydantic

def get_my_custom_validator(field_name: str) -> classmethod:
    @pydantic.validator(field_name, allow_reuse=True)
    def my_custom_validator(cls, v: int) -> int:
        return v

    return my_custom_validator

def foo():
    class MyModel(pydantic.BaseModel):
        number: int
        custom_validator = get_my_custom_validator("number")
        # custom_validator: classmethod = get_my_custom_validator("number")  # does not crash

    pass
```


### Python, Pydantic & OS Version

```Text
pydantic version: 1.10.7
            pydantic compiled: True
                 install path: /home/.../.cache/pypoetry/virtualenvs/...-aO4xbsjX-py3.10/lib/python3.10/site-packages/pydantic
               python version: 3.10.4 (main, Apr 27 2022, 18:18:04) [GCC 9.4.0]
                     platform: Linux-5.14.0-1054-oem-x86_64-with-glibc2.35
     optional deps. installed: ['dotenv', 'typing-extensions']


mypy: both 1.0.1 and 1.1.1 give the same error


pyproject.toml configuration:

[tool.mypy]
python_version = "3.10"

plugins = [
  "pydantic.mypy"
]

check_untyped_defs = true
ignore_missing_imports = true
namespace_packages = true
strict = true

disallow_any_generics = false
disallow_incomplete_defs = false
disallow_subclassing_any = false
disallow_untyped_calls = false
disallow_untyped_decorators = false
disallow_untyped_defs = false
no_implicit_optional = false
no_implicit_reexport = false
strict_equality = false
warn_return_any = false
warn_redundant_casts = true
warn_unused_ignores = true

[tool.pydantic-mypy]
init_forbid_extra = true
init_typed = true
warn_required_dynamic_aliases = true
warn_untyped_fields = false
```


### 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/)
- [ ] [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/)
- [ ] [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
- [X] [Plugins](https://docs.pydantic.dev/) and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.


Comments:

Patch:
diff --git a/pydantic/mypy.py b/pydantic/mypy.py
--- a/pydantic/mypy.py
+++ b/pydantic/mypy.py
@@ -307,15 +307,11 @@ def transform(self) -> None:
         * stores the fields, config, and if the class is settings in the mypy metadata for access by subclasses
         """
         ctx = self._ctx
-        info = self._ctx.cls.info
+        info = ctx.cls.info
 
         self.adjust_validator_signatures()
         config = self.collect_config()
         fields = self.collect_fields(config)
-        for field in fields:
-            if info[field.name].type is None:
-                if not ctx.api.final_iteration:
-                    ctx.api.defer()
         is_settings = any(get_fullname(base) == BASESETTINGS_FULLNAME for base in info.mro[:-1])
         self.add_initializer(fields, config, is_settings)
         self.add_construct_method(fields)


Test patch:
diff --git a/tests/mypy/modules/plugin_success.py b/tests/mypy/modules/plugin_success.py
--- a/tests/mypy/modules/plugin_success.py
+++ b/tests/mypy/modules/plugin_success.py
@@ -262,3 +262,19 @@ class Sample(BaseModel):
 
 
 Sample(foo='hello world')
+
+
+def get_my_custom_validator(field_name: str) -> Any:
+    @validator(field_name, allow_reuse=True)
+    def my_custom_validator(cls: Any, v: int) -> int:
+        return v
+
+    return my_custom_validator
+
+
+def foo() -> None:
+    class MyModel(BaseModel):
+        number: int
+        custom_validator = get_my_custom_validator('number')
+
+    MyModel(number=2)
diff --git a/tests/mypy/outputs/plugin-success-strict.txt b/tests/mypy/outputs/plugin-success-strict.txt
--- a/tests/mypy/outputs/plugin-success-strict.txt
+++ b/tests/mypy/outputs/plugin-success-strict.txt
@@ -1,3 +1,4 @@
 30: error: Unexpected keyword argument "z" for "Model"  [call-arg]
 65: error: Untyped fields disallowed  [pydantic-field]
 80: error: Argument "x" to "OverrideModel" has incompatible type "float"; expected "int"  [arg-type]
+278: error: Untyped fields disallowed  [pydantic-field]
diff --git a/tests/mypy/test_mypy.py b/tests/mypy/test_mypy.py
--- a/tests/mypy/test_mypy.py
+++ b/tests/mypy/test_mypy.py
@@ -64,7 +64,15 @@ def test_mypy_results(config_filename: str, python_filename: str, output_filenam
     # Specifying a different cache dir for each configuration dramatically speeds up subsequent execution
     # It also prevents cache-invalidation-related bugs in the tests
     cache_dir = f'.mypy_cache/test-{os.path.splitext(config_filename)[0]}'
-    command = [full_filename, '--config-file', full_config_filename, '--cache-dir', cache_dir, '--show-error-codes']
+    command = [
+        full_filename,
+        '--config-file',
+        full_config_filename,
+        '--cache-dir',
+        cache_dir,
+        '--show-error-codes',
+        '--show-traceback',
+    ]
     print(f"\nExecuting: mypy {' '.join(command)}")  # makes it easier to debug as necessary
     actual_result = mypy_api.run(command)
     actual_out, actual_err, actual_returncode = actual_result