Skip to content

[red-knot] Emit errors for more AST nodes that are invalid (or only valid in specific contexts) in type expressions #16822

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

MatthewMckee4
Copy link
Contributor

@MatthewMckee4 MatthewMckee4 commented Mar 17, 2025

Summary

Add error messages for invalid nodes in type expressions

Fixes #16816

Test Plan

Extend annotations/invalid.md to handle these invalid AST nodes error messages

… and added errors for invalid BoolOp and Named type expressions
@@ -6033,16 +6033,19 @@ impl<'db> TypeInferenceBuilder<'db> {
annotation_ty
}

fn report_invalid_type_expression(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlexWaygood What do you think of making this a instance method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was having issues with mutable references in ast::Expr::BoolOp as infer_boolean_expression requires a mutable reference to self, and i believe the closure does too

Copy link
Contributor

github-actions bot commented Mar 17, 2025

mypy_primer results

No ecosystem changes detected ✅

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Mar 17, 2025
@MatthewMckee4
Copy link
Contributor Author

I havent covered slice type expression yet

@MatthewMckee4
Copy link
Contributor Author

I believe tests failing is mainly due to Callable type inference calls this function with tuple expression instead of the individual arguments, ill look into this more

@MatthewMckee4
Copy link
Contributor Author

The errors mainly stem from "Tuples are not allowed in type expressions"

In generic arguments with > 1 generic parameter

I'm not really sure the best way to handle this.

Perhaps we can create a new function that can call infer_type_expression_no_store if no tuples are expected in the Expr and else it can try to "flatten" the type and / or call infer_type_expression_no_store on each type in the Tuple
*or infer_type_expression

@AlexWaygood What are your thoughts?

@dhruvmanila
Copy link
Member

I believe tests failing is mainly due to Callable type inference calls this function with tuple expression instead of the individual arguments, ill look into this more

Yeah, I haven't looked at the test failures but I think those are correct because we fallback to calling infer_type_expression for the slice expression if it's an invalid type form for a specific special form like Callable. For example:

let [first_argument, second_argument] = arguments.as_slice() else {
report_invalid_arguments_to_callable(self.db(), &self.context, subscript);
self.infer_type_expression(arguments_slice);
return Type::Callable(CallableType::General(GeneralCallableType::unknown(
self.db(),
)));
};

This is a requirement because currently the tests require that every expression has an inferred type even in the case of failure:

fn pull_types(db: &ProjectDatabase, file: File) {
let mut visitor = PullTypesVisitor::new(db, file);
let ast = parsed_module(db, file);
visitor.visit_body(ast.suite());
}

@MatthewMckee4
Copy link
Contributor Author

    fn infer_type_expression_or_tuple_type_expression(
        &mut self,
        expression: &ast::Expr,
    ) -> Type<'db> {
        match expression {
            ast::Expr::Tuple(ast::ExprTuple {
                elts: expressions, ..
            }) => Type::Tuple(TupleType::new(
                self.db(),
                expressions
                    .iter()
                    .map(|expression| self.infer_type_expression(expression))
                    .collect::<Box<_>>(),
            )),
            _ => self.infer_type_expression(expression),
        }
    }

This was sort of what i was thinking, and anywhere we call infer_type_expression and want to allow tuple expressions, we can call this. This is useful for

            KnownInstanceType::Dict => {
                self.infer_type_expression(arguments_slice);
                KnownClass::Dict.to_instance(self.db())
            }

Where if we used infer_type_expression_or_tuple_type_expression, we can actually get the Type of the tuple back, for the future as these generics are currently not supported. But for KnownInstaneType::List, we continue to use infer_type_expression

@AlexWaygood
Copy link
Member

I'd be inclined to postpone the complicated ones like Expr::Tuple and Expr::List for now and just do the easy ones in this PR -- we can tackle the complicated ones in followup(s). PRs are cheap! :-)

@MatthewMckee4
Copy link
Contributor Author

Okay can revert them to no error message

@MatthewMckee4 MatthewMckee4 marked this pull request as ready for review March 18, 2025 12:01
Copy link
Contributor

github-actions bot commented Mar 18, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

@carljm
Copy link
Contributor

carljm commented Mar 18, 2025

LGTM, thank you! Will leave it for @AlexWaygood to merge in case he has any review comments.

@MatthewMckee4
Copy link
Contributor Author

I need to test Slice node and ill also improve some error messages

@carljm
Copy link
Contributor

carljm commented Mar 18, 2025

FWIW I'm not personally a big fan of providing arbitrary "examples" in the error messages ("like 1 := 'foo'", "like 1 < 2") in the error messages. It seems a bit arbitrary what kind of example to select, it seems confusing to me to give specific code examples that don't actually come from the user's code, and it seems unnecessary because, by definition, we already have a suitable example at hand: the one from the user's code that we are emitting the diagnostic on!

So I would be inclined to remove these from the error messages, but open to what others think.

@MatthewMckee4
Copy link
Contributor Author

That's fair, my thinking was that "Unary operations", and others, could a bit vague for some users.

Then again, you could argue, people who find themselves writing these examples in type expressions, probably know what they are called.

I'm happy to revert either way

@carljm
Copy link
Contributor

carljm commented Mar 18, 2025

I think the strongest argument against is that the diagnostic will literally always be pointing to a specific example in the user's code, which seems like it should make things pretty clear.

Given Alex's thumbs-up above, yeah I think you should go ahead and remove these from the messages.

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, this is great! I pushed a couple of nitpick changes, but nothing major.

@AlexWaygood AlexWaygood enabled auto-merge (squash) March 18, 2025 17:12
@AlexWaygood AlexWaygood merged commit ab3ec4d into astral-sh:main Mar 18, 2025
22 checks passed
@MatthewMckee4 MatthewMckee4 deleted the emit-errors-for-invalid-type-expressions branch March 18, 2025 17:18
dcreager added a commit that referenced this pull request Mar 18, 2025
* main:
  [playground] Avoid concurrent deployments (#16834)
  [red-knot] Infer `lambda` return type as `Unknown` (#16695)
  [red-knot] Move `name` field on parameter kind (#16830)
  [red-knot] Emit errors for more AST nodes that are invalid (or only valid in specific contexts) in type expressions (#16822)
  [playground] Use cursor for clickable elements (#16833)
  [red-knot] Deploy playground on main (#16832)
  Red Knot Playground (#12681)
  [syntax-errors] PEP 701 f-strings before Python 3.12 (#16543)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ty Multi-file analysis & type inference
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[red-knot] Emit errors for more AST nodes that are invalid (or only valid in specific contexts) in type expressions
4 participants