[ty] Disallow Final in function parameter/return-type annotations (#19480)

## Summary

Disallow `Final` in function parameter- and return-type annotations.

[Typing
spec](https://typing.python.org/en/latest/spec/qualifiers.html#uppercase-final):

> `Final` may only be used in assignments or variable annotations. Using
it in any other position is an error. In particular, `Final` can’t be
used in annotations for function arguments

## Test Plan

Updated MD test
This commit is contained in:
David Peter 2025-07-22 13:15:19 +02:00 committed by GitHub
parent 9d98a66f65
commit 9180cd094d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 43 additions and 6 deletions

View file

@ -2219,7 +2219,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
.as_deref()
.expect("function type params scope without type params");
self.infer_optional_annotation_expression(
self.infer_return_type_annotation(
function.returns.as_deref(),
DeferredExpressionState::None,
);
@ -2581,7 +2581,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
if self.defer_annotations() {
self.deferred.insert(definition);
} else {
self.infer_optional_annotation_expression(
self.infer_return_type_annotation(
returns.as_deref(),
DeferredExpressionState::None,
);
@ -2638,6 +2638,24 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
);
}
fn infer_return_type_annotation(
&mut self,
returns: Option<&ast::Expr>,
deferred_expression_state: DeferredExpressionState,
) {
if let Some(returns) = returns {
let annotated = self.infer_annotation_expression(returns, deferred_expression_state);
if annotated.qualifiers.contains(TypeQualifiers::FINAL) {
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, returns) {
builder.into_diagnostic(
"`Final` is not allowed in function return type annotations",
);
}
}
}
}
fn infer_parameters(&mut self, parameters: &ast::Parameters) {
let ast::Parameters {
range: _,
@ -2668,10 +2686,16 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
default: _,
} = parameter_with_default;
self.infer_optional_annotation_expression(
let annotated = self.infer_optional_annotation_expression(
parameter.annotation.as_deref(),
DeferredExpressionState::None,
);
if annotated.is_some_and(|annotated| annotated.qualifiers.contains(TypeQualifiers::FINAL)) {
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, parameter) {
builder.into_diagnostic("`Final` is not allowed in function parameter annotations");
}
}
}
fn infer_parameter(&mut self, parameter: &ast::Parameter) {
@ -2956,7 +2980,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
}
fn infer_function_deferred(&mut self, function: &ast::StmtFunctionDef) {
self.infer_optional_annotation_expression(
self.infer_return_type_annotation(
function.returns.as_deref(),
DeferredExpressionState::Deferred,
);