mirror of https://github.com/astral-sh/ruff
Merge branch 'main' into alex/protocol-property-check-2
This commit is contained in:
commit
f57ea60d05
|
|
@ -213,3 +213,17 @@ async def get_id_pydantic_full(
|
||||||
async def get_id_pydantic_short(params: Annotated[PydanticParams, Depends()]): ...
|
async def get_id_pydantic_short(params: Annotated[PydanticParams, Depends()]): ...
|
||||||
@app.get("/{my_id}")
|
@app.get("/{my_id}")
|
||||||
async def get_id_init_not_annotated(params = Depends(InitParams)): ...
|
async def get_id_init_not_annotated(params = Depends(InitParams)): ...
|
||||||
|
|
||||||
|
@app.get("/things/{ thing_id }")
|
||||||
|
async def read_thing(query: str):
|
||||||
|
return {"query": query}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/things/{ thing_id : path }")
|
||||||
|
async def read_thing(query: str):
|
||||||
|
return {"query": query}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/things/{ thing_id : str }")
|
||||||
|
async def read_thing(query: str):
|
||||||
|
return {"query": query}
|
||||||
|
|
|
||||||
|
|
@ -192,3 +192,24 @@ def issue_19005_3():
|
||||||
c = {}
|
c = {}
|
||||||
for a[0], a[1] in ():
|
for a[0], a[1] in ():
|
||||||
c[a[0]] = a[1]
|
c[a[0]] = a[1]
|
||||||
|
|
||||||
|
|
||||||
|
def issue_19153_1():
|
||||||
|
v = {}
|
||||||
|
for o, (x,) in ["ox"]:
|
||||||
|
v[x,] = o
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def issue_19153_2():
|
||||||
|
v = {}
|
||||||
|
for (o, p), x in [("op", "x")]:
|
||||||
|
v[x] = o, p
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def issue_19153_3():
|
||||||
|
v = {}
|
||||||
|
for o, (x,) in ["ox"]:
|
||||||
|
v[(x,)] = o
|
||||||
|
return v
|
||||||
|
|
@ -4,6 +4,9 @@ print("שלום")
|
||||||
# E2502
|
# E2502
|
||||||
example = "x" * 100 # "x" is assigned
|
example = "x" * 100 # "x" is assigned
|
||||||
|
|
||||||
|
# E2502
|
||||||
|
another = "x" * 50 # "x" is assigned
|
||||||
|
|
||||||
# E2502
|
# E2502
|
||||||
if access_level != "none": # Check if admin ' and access_level != 'user
|
if access_level != "none": # Check if admin ' and access_level != 'user
|
||||||
print("You are an admin.")
|
print("You are an admin.")
|
||||||
|
|
|
||||||
|
|
@ -107,3 +107,6 @@ deque(f"{x}" "") # OK
|
||||||
deque(t"")
|
deque(t"")
|
||||||
deque(t"" t"")
|
deque(t"" t"")
|
||||||
deque(t"{""}") # OK
|
deque(t"{""}") # OK
|
||||||
|
|
||||||
|
# https://github.com/astral-sh/ruff/issues/20050
|
||||||
|
deque(f"{""}") # RUF037
|
||||||
|
|
|
||||||
|
|
@ -255,3 +255,8 @@ pub(crate) const fn is_trailing_comma_type_params_enabled(settings: &LinterSetti
|
||||||
pub(crate) const fn is_maxsplit_without_separator_fix_enabled(settings: &LinterSettings) -> bool {
|
pub(crate) const fn is_maxsplit_without_separator_fix_enabled(settings: &LinterSettings) -> bool {
|
||||||
settings.preview.is_enabled()
|
settings.preview.is_enabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/astral-sh/ruff/pull/20106
|
||||||
|
pub(crate) const fn is_bidi_forbid_arabic_letter_mark_enabled(settings: &LinterSettings) -> bool {
|
||||||
|
settings.preview.is_enabled()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -457,6 +457,9 @@ fn parameter_alias<'a>(parameter: &'a Parameter, semantic: &SemanticModel) -> Op
|
||||||
///
|
///
|
||||||
/// The iterator yields tuples of the parameter name and the range of the parameter in the input,
|
/// The iterator yields tuples of the parameter name and the range of the parameter in the input,
|
||||||
/// inclusive of curly braces.
|
/// inclusive of curly braces.
|
||||||
|
///
|
||||||
|
/// FastAPI only recognizes path parameters when there are no leading or trailing spaces around
|
||||||
|
/// the parameter name. For example, `/{x}` is a valid parameter, but `/{ x }` is treated literally.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct PathParamIterator<'a> {
|
struct PathParamIterator<'a> {
|
||||||
input: &'a str,
|
input: &'a str,
|
||||||
|
|
@ -483,7 +486,7 @@ impl<'a> Iterator for PathParamIterator<'a> {
|
||||||
// We ignore text after a colon, since those are path converters
|
// We ignore text after a colon, since those are path converters
|
||||||
// See also: https://fastapi.tiangolo.com/tutorial/path-params/?h=path#path-convertor
|
// See also: https://fastapi.tiangolo.com/tutorial/path-params/?h=path#path-convertor
|
||||||
let param_name_end = param_content.find(':').unwrap_or(param_content.len());
|
let param_name_end = param_content.find(':').unwrap_or(param_content.len());
|
||||||
let param_name = ¶m_content[..param_name_end].trim();
|
let param_name = ¶m_content[..param_name_end];
|
||||||
|
|
||||||
#[expect(clippy::range_plus_one)]
|
#[expect(clippy::range_plus_one)]
|
||||||
return Some((param_name, start..end + 1));
|
return Some((param_name, start..end + 1));
|
||||||
|
|
|
||||||
|
|
@ -59,25 +59,6 @@ help: Add `thing_id` to function signature
|
||||||
23 |
|
23 |
|
||||||
note: This is an unsafe fix and may change runtime behavior
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
FAST003 [*] Parameter `thing_id` appears in route path, but not in `read_thing` signature
|
|
||||||
--> FAST003.py:24:19
|
|
||||||
|
|
|
||||||
24 | @app.get("/things/{thing_id : path}")
|
|
||||||
| ^^^^^^^^^^^^^^^^^
|
|
||||||
25 | async def read_thing(query: str):
|
|
||||||
26 | return {"query": query}
|
|
||||||
|
|
|
||||||
help: Add `thing_id` to function signature
|
|
||||||
22 |
|
|
||||||
23 |
|
|
||||||
24 | @app.get("/things/{thing_id : path}")
|
|
||||||
- async def read_thing(query: str):
|
|
||||||
25 + async def read_thing(query: str, thing_id):
|
|
||||||
26 | return {"query": query}
|
|
||||||
27 |
|
|
||||||
28 |
|
|
||||||
note: This is an unsafe fix and may change runtime behavior
|
|
||||||
|
|
||||||
FAST003 [*] Parameter `title` appears in route path, but not in `read_thing` signature
|
FAST003 [*] Parameter `title` appears in route path, but not in `read_thing` signature
|
||||||
--> FAST003.py:29:27
|
--> FAST003.py:29:27
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -354,21 +354,37 @@ fn convert_to_dict_comprehension(
|
||||||
"for"
|
"for"
|
||||||
};
|
};
|
||||||
// Handles the case where `key` has a trailing comma, e.g, `dict[x,] = y`
|
// Handles the case where `key` has a trailing comma, e.g, `dict[x,] = y`
|
||||||
let key_range = if let Expr::Tuple(ast::ExprTuple { elts, .. }) = key {
|
let key_str = if let Expr::Tuple(ast::ExprTuple {
|
||||||
let [expr] = elts.as_slice() else {
|
elts,
|
||||||
|
parenthesized,
|
||||||
|
..
|
||||||
|
}) = key
|
||||||
|
{
|
||||||
|
if elts.len() != 1 {
|
||||||
return None;
|
return None;
|
||||||
};
|
}
|
||||||
expr.range()
|
if *parenthesized {
|
||||||
|
locator.slice(key).to_string()
|
||||||
|
} else {
|
||||||
|
format!("({})", locator.slice(key))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
key.range()
|
locator.slice(key).to_string()
|
||||||
};
|
};
|
||||||
let elt_str = format!(
|
|
||||||
"{}: {}",
|
|
||||||
locator.slice(key_range),
|
|
||||||
locator.slice(value.range())
|
|
||||||
);
|
|
||||||
|
|
||||||
let comprehension_str = format!("{{{elt_str} {for_type} {target_str} in {iter_str}{if_str}}}");
|
// If the value is a tuple without parentheses, add them
|
||||||
|
let value_str = if let Expr::Tuple(ast::ExprTuple {
|
||||||
|
parenthesized: false,
|
||||||
|
..
|
||||||
|
}) = value
|
||||||
|
{
|
||||||
|
format!("({})", locator.slice(value))
|
||||||
|
} else {
|
||||||
|
locator.slice(value).to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let comprehension_str =
|
||||||
|
format!("{{{key_str}: {value_str} {for_type} {target_str} in {iter_str}{if_str}}}");
|
||||||
|
|
||||||
let for_loop_inline_comments = comment_strings_in_range(
|
let for_loop_inline_comments = comment_strings_in_range(
|
||||||
checker,
|
checker,
|
||||||
|
|
|
||||||
|
|
@ -176,3 +176,36 @@ PERF403 Use a dictionary comprehension instead of a for-loop
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
help: Replace for loop with dict comprehension
|
help: Replace for loop with dict comprehension
|
||||||
|
|
||||||
|
PERF403 Use a dictionary comprehension instead of a for-loop
|
||||||
|
--> PERF403.py:200:9
|
||||||
|
|
|
||||||
|
198 | v = {}
|
||||||
|
199 | for o, (x,) in ["ox"]:
|
||||||
|
200 | v[x,] = o
|
||||||
|
| ^^^^^^^^^
|
||||||
|
201 | return v
|
||||||
|
|
|
||||||
|
help: Replace for loop with dict comprehension
|
||||||
|
|
||||||
|
PERF403 Use a dictionary comprehension instead of a for-loop
|
||||||
|
--> PERF403.py:207:9
|
||||||
|
|
|
||||||
|
205 | v = {}
|
||||||
|
206 | for (o, p), x in [("op", "x")]:
|
||||||
|
207 | v[x] = o, p
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
208 | return v
|
||||||
|
|
|
||||||
|
help: Replace for loop with dict comprehension
|
||||||
|
|
||||||
|
PERF403 Use a dictionary comprehension instead of a for-loop
|
||||||
|
--> PERF403.py:214:9
|
||||||
|
|
|
||||||
|
212 | v = {}
|
||||||
|
213 | for o, (x,) in ["ox"]:
|
||||||
|
214 | v[(x,)] = o
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
215 | return v
|
||||||
|
|
|
||||||
|
help: Replace for loop with dict comprehension
|
||||||
|
|
|
||||||
|
|
@ -372,8 +372,72 @@ help: Replace for loop with dict comprehension
|
||||||
- v = {}
|
- v = {}
|
||||||
- for o,(x,)in():
|
- for o,(x,)in():
|
||||||
- v[x,]=o
|
- v[x,]=o
|
||||||
170 + v = {x: o for o,(x,) in ()}
|
170 + v = {(x,): o for o,(x,) in ()}
|
||||||
171 |
|
171 |
|
||||||
172 |
|
172 |
|
||||||
173 | # https://github.com/astral-sh/ruff/issues/19005
|
173 | # https://github.com/astral-sh/ruff/issues/19005
|
||||||
note: This is an unsafe fix and may change runtime behavior
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
PERF403 [*] Use a dictionary comprehension instead of a for-loop
|
||||||
|
--> PERF403.py:200:9
|
||||||
|
|
|
||||||
|
198 | v = {}
|
||||||
|
199 | for o, (x,) in ["ox"]:
|
||||||
|
200 | v[x,] = o
|
||||||
|
| ^^^^^^^^^
|
||||||
|
201 | return v
|
||||||
|
|
|
||||||
|
help: Replace for loop with dict comprehension
|
||||||
|
195 |
|
||||||
|
196 |
|
||||||
|
197 | def issue_19153_1():
|
||||||
|
- v = {}
|
||||||
|
- for o, (x,) in ["ox"]:
|
||||||
|
- v[x,] = o
|
||||||
|
198 + v = {(x,): o for o, (x,) in ["ox"]}
|
||||||
|
199 | return v
|
||||||
|
200 |
|
||||||
|
201 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
PERF403 [*] Use a dictionary comprehension instead of a for-loop
|
||||||
|
--> PERF403.py:207:9
|
||||||
|
|
|
||||||
|
205 | v = {}
|
||||||
|
206 | for (o, p), x in [("op", "x")]:
|
||||||
|
207 | v[x] = o, p
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
208 | return v
|
||||||
|
|
|
||||||
|
help: Replace for loop with dict comprehension
|
||||||
|
202 |
|
||||||
|
203 |
|
||||||
|
204 | def issue_19153_2():
|
||||||
|
- v = {}
|
||||||
|
- for (o, p), x in [("op", "x")]:
|
||||||
|
- v[x] = o, p
|
||||||
|
205 + v = {x: (o, p) for (o, p), x in [("op", "x")]}
|
||||||
|
206 | return v
|
||||||
|
207 |
|
||||||
|
208 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
PERF403 [*] Use a dictionary comprehension instead of a for-loop
|
||||||
|
--> PERF403.py:214:9
|
||||||
|
|
|
||||||
|
212 | v = {}
|
||||||
|
213 | for o, (x,) in ["ox"]:
|
||||||
|
214 | v[(x,)] = o
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
215 | return v
|
||||||
|
|
|
||||||
|
help: Replace for loop with dict comprehension
|
||||||
|
209 |
|
||||||
|
210 |
|
||||||
|
211 | def issue_19153_3():
|
||||||
|
- v = {}
|
||||||
|
- for o, (x,) in ["ox"]:
|
||||||
|
- v[(x,)] = o
|
||||||
|
212 + v = {(x,): o for o, (x,) in ["ox"]}
|
||||||
|
213 | return v
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,30 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case(Rule::BidirectionalUnicode, Path::new("bidirectional_unicode.py"))]
|
||||||
|
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
|
let snapshot = format!(
|
||||||
|
"preview__{}_{}",
|
||||||
|
rule_code.noqa_code(),
|
||||||
|
path.to_string_lossy()
|
||||||
|
);
|
||||||
|
let diagnostics = test_path(
|
||||||
|
Path::new("pylint").join(path).as_path(),
|
||||||
|
&LinterSettings {
|
||||||
|
pylint: pylint::settings::Settings {
|
||||||
|
allow_dunder_method_names: FxHashSet::from_iter([
|
||||||
|
"__special_custom_magic__".to_string()
|
||||||
|
]),
|
||||||
|
..pylint::settings::Settings::default()
|
||||||
|
},
|
||||||
|
preview: PreviewMode::Enabled,
|
||||||
|
..LinterSettings::for_rule(rule_code)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
assert_diagnostics!(snapshot, diagnostics);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn continue_in_finally() -> Result<()> {
|
fn continue_in_finally() -> Result<()> {
|
||||||
let diagnostics = test_path(
|
let diagnostics = test_path(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_source_file::Line;
|
use ruff_source_file::Line;
|
||||||
|
|
||||||
use crate::{Violation, checkers::ast::LintContext};
|
use crate::{
|
||||||
|
Violation, checkers::ast::LintContext, preview::is_bidi_forbid_arabic_letter_mark_enabled,
|
||||||
|
};
|
||||||
|
|
||||||
const BIDI_UNICODE: [char; 10] = [
|
const BIDI_UNICODE: [char; 10] = [
|
||||||
'\u{202A}', //{LEFT-TO-RIGHT EMBEDDING}
|
'\u{202A}', //{LEFT-TO-RIGHT EMBEDDING}
|
||||||
|
|
@ -60,7 +62,12 @@ impl Violation for BidirectionalUnicode {
|
||||||
|
|
||||||
/// PLE2502
|
/// PLE2502
|
||||||
pub(crate) fn bidirectional_unicode(line: &Line, context: &LintContext) {
|
pub(crate) fn bidirectional_unicode(line: &Line, context: &LintContext) {
|
||||||
if line.contains(BIDI_UNICODE) {
|
if line.contains(BIDI_UNICODE)
|
||||||
|
|| (is_bidi_forbid_arabic_letter_mark_enabled(context.settings())
|
||||||
|
&& line.contains(
|
||||||
|
'\u{061C}', //{ARABIC LETTER MARK}
|
||||||
|
))
|
||||||
|
{
|
||||||
context.report_diagnostic(BidirectionalUnicode, line.full_range());
|
context.report_diagnostic(BidirectionalUnicode, line.full_range());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,21 +22,21 @@ PLE2502 Contains control characters that can permit obfuscated code
|
||||||
|
|
|
|
||||||
|
|
||||||
PLE2502 Contains control characters that can permit obfuscated code
|
PLE2502 Contains control characters that can permit obfuscated code
|
||||||
--> bidirectional_unicode.py:8:1
|
--> bidirectional_unicode.py:11:1
|
||||||
|
|
|
|
||||||
7 | # E2502
|
10 | # E2502
|
||||||
8 | if access_level != "none": # Check if admin ' and access_level != 'user
|
11 | if access_level != "none": # Check if admin ' and access_level != 'user
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
9 | print("You are an admin.")
|
12 | print("You are an admin.")
|
||||||
|
|
|
|
||||||
|
|
||||||
PLE2502 Contains control characters that can permit obfuscated code
|
PLE2502 Contains control characters that can permit obfuscated code
|
||||||
--> bidirectional_unicode.py:14:1
|
--> bidirectional_unicode.py:17:1
|
||||||
|
|
|
|
||||||
12 | # E2502
|
15 | # E2502
|
||||||
13 | def subtract_funds(account: str, amount: int):
|
16 | def subtract_funds(account: str, amount: int):
|
||||||
14 | """Subtract funds from bank account then """
|
17 | """Subtract funds from bank account then """
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
15 | return
|
18 | return
|
||||||
16 | bank[account] -= amount
|
19 | bank[account] -= amount
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pylint/mod.rs
|
||||||
|
---
|
||||||
|
PLE2502 Contains control characters that can permit obfuscated code
|
||||||
|
--> bidirectional_unicode.py:2:1
|
||||||
|
|
|
||||||
|
1 | # E2502
|
||||||
|
2 | print("שלום")
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
3 |
|
||||||
|
4 | # E2502
|
||||||
|
|
|
||||||
|
|
||||||
|
PLE2502 Contains control characters that can permit obfuscated code
|
||||||
|
--> bidirectional_unicode.py:5:1
|
||||||
|
|
|
||||||
|
4 | # E2502
|
||||||
|
5 | example = "x" * 100 # "x" is assigned
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
6 |
|
||||||
|
7 | # E2502
|
||||||
|
|
|
||||||
|
|
||||||
|
PLE2502 Contains control characters that can permit obfuscated code
|
||||||
|
--> bidirectional_unicode.py:8:1
|
||||||
|
|
|
||||||
|
7 | # E2502
|
||||||
|
8 | another = "x" * 50 # "x" is assigned
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
9 |
|
||||||
|
10 | # E2502
|
||||||
|
|
|
||||||
|
|
||||||
|
PLE2502 Contains control characters that can permit obfuscated code
|
||||||
|
--> bidirectional_unicode.py:11:1
|
||||||
|
|
|
||||||
|
10 | # E2502
|
||||||
|
11 | if access_level != "none": # Check if admin ' and access_level != 'user
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
12 | print("You are an admin.")
|
||||||
|
|
|
||||||
|
|
||||||
|
PLE2502 Contains control characters that can permit obfuscated code
|
||||||
|
--> bidirectional_unicode.py:17:1
|
||||||
|
|
|
||||||
|
15 | # E2502
|
||||||
|
16 | def subtract_funds(account: str, amount: int):
|
||||||
|
17 | """Subtract funds from bank account then """
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
18 | return
|
||||||
|
19 | bank[account] -= amount
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,11 @@ use crate::{Applicability, Edit, Fix, FixAvailability, Violation};
|
||||||
/// print()
|
/// print()
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// ## Fix safety
|
||||||
|
/// This fix is marked as unsafe if it removes an unused `sep` keyword argument
|
||||||
|
/// that may have side effects. Removing such arguments may change the program's
|
||||||
|
/// behavior by skipping the execution of those side effects.
|
||||||
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [Python documentation: `print`](https://docs.python.org/3/library/functions.html#print)
|
/// - [Python documentation: `print`](https://docs.python.org/3/library/functions.html#print)
|
||||||
#[derive(ViolationMetadata)]
|
#[derive(ViolationMetadata)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use ruff_diagnostics::{Applicability, Edit};
|
use ruff_diagnostics::{Applicability, Edit};
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
|
||||||
|
use ruff_python_ast::helpers::is_empty_f_string;
|
||||||
use ruff_python_ast::parenthesize::parenthesized_range;
|
use ruff_python_ast::parenthesize::parenthesized_range;
|
||||||
use ruff_python_ast::{self as ast, Expr};
|
use ruff_python_ast::{self as ast, Expr};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
@ -102,7 +104,7 @@ pub(crate) fn unnecessary_literal_within_deque_call(checker: &Checker, deque: &a
|
||||||
}
|
}
|
||||||
Expr::StringLiteral(string) => string.value.is_empty(),
|
Expr::StringLiteral(string) => string.value.is_empty(),
|
||||||
Expr::BytesLiteral(bytes) => bytes.value.is_empty(),
|
Expr::BytesLiteral(bytes) => bytes.value.is_empty(),
|
||||||
Expr::FString(fstring) => fstring.value.is_empty_literal(),
|
Expr::FString(fstring) => is_empty_f_string(fstring),
|
||||||
Expr::TString(tstring) => tstring.value.is_empty_iterable(),
|
Expr::TString(tstring) => tstring.value.is_empty_iterable(),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -369,6 +369,7 @@ help: Replace with `deque()`
|
||||||
107 + deque()
|
107 + deque()
|
||||||
108 | deque(t"" t"")
|
108 | deque(t"" t"")
|
||||||
109 | deque(t"{""}") # OK
|
109 | deque(t"{""}") # OK
|
||||||
|
110 |
|
||||||
|
|
||||||
RUF037 [*] Unnecessary empty iterable within a deque call
|
RUF037 [*] Unnecessary empty iterable within a deque call
|
||||||
--> RUF037.py:108:1
|
--> RUF037.py:108:1
|
||||||
|
|
@ -386,3 +387,19 @@ help: Replace with `deque()`
|
||||||
- deque(t"" t"")
|
- deque(t"" t"")
|
||||||
108 + deque()
|
108 + deque()
|
||||||
109 | deque(t"{""}") # OK
|
109 | deque(t"{""}") # OK
|
||||||
|
110 |
|
||||||
|
111 | # https://github.com/astral-sh/ruff/issues/20050
|
||||||
|
|
||||||
|
RUF037 [*] Unnecessary empty iterable within a deque call
|
||||||
|
--> RUF037.py:112:1
|
||||||
|
|
|
||||||
|
111 | # https://github.com/astral-sh/ruff/issues/20050
|
||||||
|
112 | deque(f"{""}") # RUF037
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: Replace with `deque()`
|
||||||
|
109 | deque(t"{""}") # OK
|
||||||
|
110 |
|
||||||
|
111 | # https://github.com/astral-sh/ruff/issues/20050
|
||||||
|
- deque(f"{""}") # RUF037
|
||||||
|
112 + deque() # RUF037
|
||||||
|
|
|
||||||
|
|
@ -1406,7 +1406,7 @@ fn is_non_empty_f_string(expr: &ast::ExprFString) -> bool {
|
||||||
|
|
||||||
/// Returns `true` if the expression definitely resolves to the empty string, when used as an f-string
|
/// Returns `true` if the expression definitely resolves to the empty string, when used as an f-string
|
||||||
/// expression.
|
/// expression.
|
||||||
fn is_empty_f_string(expr: &ast::ExprFString) -> bool {
|
pub fn is_empty_f_string(expr: &ast::ExprFString) -> bool {
|
||||||
fn inner(expr: &Expr) -> bool {
|
fn inner(expr: &Expr) -> bool {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.is_empty(),
|
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.is_empty(),
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ def test(): -> "int":
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L112)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L113)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -58,7 +58,7 @@ Calling a non-callable object will raise a `TypeError` at runtime.
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L156)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L157)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -88,7 +88,7 @@ f(int) # error
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L182)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L183)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -117,7 +117,7 @@ a = 1
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L207)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L208)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -147,7 +147,7 @@ class C(A, B): ...
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L233)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L234)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -177,7 +177,7 @@ class B(A): ...
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L298)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L299)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -202,7 +202,7 @@ class B(A, A): ...
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-kw-only) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-kw-only) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L319)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L320)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -306,7 +306,7 @@ def test(): -> "Literal[5]":
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L522)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L523)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -334,7 +334,7 @@ class C(A, B): ...
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L546)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L547)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -358,7 +358,7 @@ t[3] # IndexError: tuple index out of range
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20instance-layout-conflict) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20instance-layout-conflict) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L351)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L352)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -445,7 +445,7 @@ an atypical memory layout.
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L591)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L592)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -470,7 +470,7 @@ func("foo") # error: [invalid-argument-type]
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L631)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L632)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -496,7 +496,7 @@ a: int = ''
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1665)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1666)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -528,7 +528,7 @@ C.instance_var = 3 # error: Cannot assign to instance variable
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-await) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-await) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L653)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L654)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -562,7 +562,7 @@ asyncio.run(main())
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L683)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L684)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -584,7 +584,7 @@ class A(42): ... # error: [invalid-base]
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L734)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L735)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -609,7 +609,7 @@ with 1:
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L755)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L756)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -636,7 +636,7 @@ a: str
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L778)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L779)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -678,7 +678,7 @@ except ZeroDivisionError:
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L814)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L815)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -709,7 +709,7 @@ class C[U](Generic[T]): ...
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-key) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-key) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L566)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L567)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -738,7 +738,7 @@ alice["height"] # KeyError: 'height'
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L840)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L841)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -771,7 +771,7 @@ def f(t: TypeVar("U")): ...
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L889)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L890)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -803,7 +803,7 @@ class B(metaclass=f): ...
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-named-tuple) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-named-tuple) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L496)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L497)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -833,7 +833,7 @@ TypeError: can only inherit from a NamedTuple type and Generic
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L916)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L917)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -881,7 +881,7 @@ def foo(x: int) -> int: ...
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L959)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L960)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -905,7 +905,7 @@ def f(a: int = ''): ...
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L433)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L434)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -937,7 +937,7 @@ TypeError: Protocols can only inherit from other protocols, got <class 'int'>
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L979)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L980)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
Checks for `raise` statements that raise non-exceptions or use invalid
|
Checks for `raise` statements that raise non-exceptions or use invalid
|
||||||
|
|
@ -984,7 +984,7 @@ def g():
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L612)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L613)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1007,7 +1007,7 @@ def func() -> int:
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1022)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1023)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1061,7 +1061,7 @@ TODO #14889
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L868)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L869)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1086,7 +1086,7 @@ NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name mus
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1061)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1062)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1114,7 +1114,7 @@ TYPE_CHECKING = ''
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1085)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1086)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1142,7 +1142,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-call) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-call) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1137)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1138)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1174,7 +1174,7 @@ f(10) # Error
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-definition) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-definition) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1109)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1110)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1206,7 +1206,7 @@ class C:
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1165)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1166)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1239,7 +1239,7 @@ T = TypeVar('T', bound=str) # valid bound TypeVar
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1194)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1195)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1262,7 +1262,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-typed-dict-key) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-typed-dict-key) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1764)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1765)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1293,7 +1293,7 @@ alice["age"] # KeyError
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1213)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1214)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1320,7 +1320,7 @@ func("string") # error: [no-matching-overload]
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1236)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1237)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1342,7 +1342,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1254)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1255)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1366,7 +1366,7 @@ for i in 34: # TypeError: 'int' object is not iterable
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1305)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1306)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1420,7 +1420,7 @@ def test(): -> "int":
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1641)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1642)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1448,7 +1448,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1396)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1397)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1475,7 +1475,7 @@ class B(A): ... # Error raised here
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1441)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1442)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1500,7 +1500,7 @@ f("foo") # Error raised here
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1419)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1420)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1526,7 +1526,7 @@ def _(x: int):
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1462)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1463)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1570,7 +1570,7 @@ class A:
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1519)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1520)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1595,7 +1595,7 @@ f(x=1, y=2) # Error raised here
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1540)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1541)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1621,7 +1621,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo'
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1562)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1563)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1644,7 +1644,7 @@ import foo # ModuleNotFoundError: No module named 'foo'
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1581)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1582)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1667,7 +1667,7 @@ print(x) # NameError: name 'x' is not defined
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1274)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1275)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1702,7 +1702,7 @@ b1 < b2 < b1 # exception raised here
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1600)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1601)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1728,7 +1728,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
|
||||||
<small>
|
<small>
|
||||||
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1622)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1623)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1751,7 +1751,7 @@ l[1:10:0] # ValueError: slice step cannot be zero
|
||||||
<small>
|
<small>
|
||||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20ambiguous-protocol-member) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20ambiguous-protocol-member) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L461)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L462)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1790,7 +1790,7 @@ class SubProto(BaseProto, Protocol):
|
||||||
<small>
|
<small>
|
||||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20deprecated) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20deprecated) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L277)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L278)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1843,7 +1843,7 @@ a = 20 / 0 # type: ignore
|
||||||
<small>
|
<small>
|
||||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-attribute) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-attribute) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1326)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1327)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1869,7 +1869,7 @@ A.c # AttributeError: type object 'A' has no attribute 'c'
|
||||||
<small>
|
<small>
|
||||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-implicit-call) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-implicit-call) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L130)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L131)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1899,7 +1899,7 @@ A()[0] # TypeError: 'A' object is not subscriptable
|
||||||
<small>
|
<small>
|
||||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-import) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-import) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1348)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1349)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1929,7 +1929,7 @@ from module import a # ImportError: cannot import name 'a' from 'module'
|
||||||
<small>
|
<small>
|
||||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1693)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1694)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -1954,7 +1954,7 @@ cast(int, f()) # Redundant
|
||||||
<small>
|
<small>
|
||||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1501)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1502)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -2005,7 +2005,7 @@ a = 20 / 0 # ty: ignore[division-by-zero]
|
||||||
<small>
|
<small>
|
||||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-global) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-global) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1714)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1715)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -2059,7 +2059,7 @@ def g():
|
||||||
<small>
|
<small>
|
||||||
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-base) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-base) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L701)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L702)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -2096,7 +2096,7 @@ class D(C): ... # error: [unsupported-base]
|
||||||
<small>
|
<small>
|
||||||
Default level: [`ignore`](../rules.md#rule-levels "This lint has a default level of 'ignore'.") ·
|
Default level: [`ignore`](../rules.md#rule-levels "This lint has a default level of 'ignore'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L259)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L260)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
@ -2118,7 +2118,7 @@ Dividing by zero raises a `ZeroDivisionError` at runtime.
|
||||||
<small>
|
<small>
|
||||||
Default level: [`ignore`](../rules.md#rule-levels "This lint has a default level of 'ignore'.") ·
|
Default level: [`ignore`](../rules.md#rule-levels "This lint has a default level of 'ignore'.") ·
|
||||||
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference) ·
|
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference) ·
|
||||||
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1374)
|
[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1375)
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
**What it does**
|
**What it does**
|
||||||
|
|
|
||||||
|
|
@ -290,16 +290,10 @@ from overloaded import A, f
|
||||||
|
|
||||||
def _(x: int, y: A | int):
|
def _(x: int, y: A | int):
|
||||||
reveal_type(f(x)) # revealed: int
|
reveal_type(f(x)) # revealed: int
|
||||||
# TODO: revealed: int
|
reveal_type(f(*(x,))) # revealed: int
|
||||||
# TODO: no error
|
|
||||||
# error: [no-matching-overload]
|
|
||||||
reveal_type(f(*(x,))) # revealed: Unknown
|
|
||||||
|
|
||||||
reveal_type(f(y)) # revealed: A | int
|
reveal_type(f(y)) # revealed: A | int
|
||||||
# TODO: revealed: A | int
|
reveal_type(f(*(y,))) # revealed: A | int
|
||||||
# TODO: no error
|
|
||||||
# error: [no-matching-overload]
|
|
||||||
reveal_type(f(*(y,))) # revealed: Unknown
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Generics (PEP 695)
|
### Generics (PEP 695)
|
||||||
|
|
@ -328,16 +322,10 @@ from overloaded import B, f
|
||||||
|
|
||||||
def _(x: int, y: B | int):
|
def _(x: int, y: B | int):
|
||||||
reveal_type(f(x)) # revealed: int
|
reveal_type(f(x)) # revealed: int
|
||||||
# TODO: revealed: int
|
reveal_type(f(*(x,))) # revealed: int
|
||||||
# TODO: no error
|
|
||||||
# error: [no-matching-overload]
|
|
||||||
reveal_type(f(*(x,))) # revealed: Unknown
|
|
||||||
|
|
||||||
reveal_type(f(y)) # revealed: B | int
|
reveal_type(f(y)) # revealed: B | int
|
||||||
# TODO: revealed: B | int
|
reveal_type(f(*(y,))) # revealed: B | int
|
||||||
# TODO: no error
|
|
||||||
# error: [no-matching-overload]
|
|
||||||
reveal_type(f(*(y,))) # revealed: Unknown
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Expanding `bool`
|
### Expanding `bool`
|
||||||
|
|
@ -1236,21 +1224,14 @@ def _(integer: int, string: str, any: Any, list_any: list[Any]):
|
||||||
reveal_type(f(*(integer, string))) # revealed: int
|
reveal_type(f(*(integer, string))) # revealed: int
|
||||||
|
|
||||||
reveal_type(f(string, integer)) # revealed: int
|
reveal_type(f(string, integer)) # revealed: int
|
||||||
# TODO: revealed: int
|
reveal_type(f(*(string, integer))) # revealed: int
|
||||||
# TODO: no error
|
|
||||||
# error: [no-matching-overload]
|
|
||||||
reveal_type(f(*(string, integer))) # revealed: Unknown
|
|
||||||
|
|
||||||
# This matches the second overload and is _not_ the case of ambiguous overload matching.
|
# This matches the second overload and is _not_ the case of ambiguous overload matching.
|
||||||
reveal_type(f(string, any)) # revealed: Any
|
reveal_type(f(string, any)) # revealed: Any
|
||||||
# TODO: Any
|
reveal_type(f(*(string, any))) # revealed: Any
|
||||||
reveal_type(f(*(string, any))) # revealed: tuple[str, Any]
|
|
||||||
|
|
||||||
reveal_type(f(string, list_any)) # revealed: list[Any]
|
reveal_type(f(string, list_any)) # revealed: list[Any]
|
||||||
# TODO: revealed: list[Any]
|
reveal_type(f(*(string, list_any))) # revealed: list[Any]
|
||||||
# TODO: no error
|
|
||||||
# error: [no-matching-overload]
|
|
||||||
reveal_type(f(*(string, list_any))) # revealed: Unknown
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Generic `self`
|
### Generic `self`
|
||||||
|
|
|
||||||
|
|
@ -522,6 +522,22 @@ c.name = None
|
||||||
c.name = 42
|
c.name = 42
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Properties with no setters
|
||||||
|
|
||||||
|
<!-- snapshot-diagnostics -->
|
||||||
|
|
||||||
|
If a property has no setter, we emit a bespoke error message when a user attempts to set that
|
||||||
|
attribute, since this is a common error.
|
||||||
|
|
||||||
|
```py
|
||||||
|
class DontAssignToMe:
|
||||||
|
@property
|
||||||
|
def immutable(self): ...
|
||||||
|
|
||||||
|
# error: [invalid-assignment]
|
||||||
|
DontAssignToMe().immutable = "the properties, they are a-changing"
|
||||||
|
```
|
||||||
|
|
||||||
### Built-in `classmethod` descriptor
|
### Built-in `classmethod` descriptor
|
||||||
|
|
||||||
Similarly to `property`, `classmethod` decorator creates an implicit descriptor that binds the first
|
Similarly to `property`, `classmethod` decorator creates an implicit descriptor that binds the first
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,11 @@ def f(cond: bool) -> int:
|
||||||
|
|
||||||
<!-- snapshot-diagnostics -->
|
<!-- snapshot-diagnostics -->
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[environment]
|
||||||
|
python-version = "3.12"
|
||||||
|
```
|
||||||
|
|
||||||
```py
|
```py
|
||||||
# error: [invalid-return-type]
|
# error: [invalid-return-type]
|
||||||
def f() -> int:
|
def f() -> int:
|
||||||
|
|
@ -279,6 +284,18 @@ T = TypeVar("T")
|
||||||
|
|
||||||
# error: [invalid-return-type]
|
# error: [invalid-return-type]
|
||||||
def m(x: T) -> T: ...
|
def m(x: T) -> T: ...
|
||||||
|
|
||||||
|
class A[T]: ...
|
||||||
|
|
||||||
|
def f() -> A[int]:
|
||||||
|
class A[T]: ...
|
||||||
|
return A[int]() # error: [invalid-return-type]
|
||||||
|
|
||||||
|
class B: ...
|
||||||
|
|
||||||
|
def g() -> B:
|
||||||
|
class B: ...
|
||||||
|
return B() # error: [invalid-return-type]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Invalid return type in stub file
|
## Invalid return type in stub file
|
||||||
|
|
|
||||||
|
|
@ -78,10 +78,7 @@ reveal_type(Person.id) # revealed: property
|
||||||
reveal_type(Person.name) # revealed: property
|
reveal_type(Person.name) # revealed: property
|
||||||
reveal_type(Person.age) # revealed: property
|
reveal_type(Person.age) # revealed: property
|
||||||
|
|
||||||
# TODO... the error is correct, but this is not the friendliest error message
|
# error: [invalid-assignment] "Attribute `id` on object of type `Person` is read-only"
|
||||||
# for assigning to a read-only property :-)
|
|
||||||
#
|
|
||||||
# error: [invalid-assignment] "Invalid assignment to data descriptor attribute `id` on type `Person` with custom `__set__` method"
|
|
||||||
alice.id = 42
|
alice.id = 42
|
||||||
# error: [invalid-assignment]
|
# error: [invalid-assignment]
|
||||||
bob.age = None
|
bob.age = None
|
||||||
|
|
@ -221,10 +218,7 @@ james = SuperUser(0, "James", 42, "Jimmy")
|
||||||
# on the subclass
|
# on the subclass
|
||||||
james.name = "Robert"
|
james.name = "Robert"
|
||||||
|
|
||||||
# TODO: the error is correct (can't assign to the read-only property inherited from the superclass)
|
# error: [invalid-assignment] "Attribute `nickname` on object of type `SuperUser` is read-only"
|
||||||
# but the error message could be friendlier :-)
|
|
||||||
#
|
|
||||||
# error: [invalid-assignment] "Invalid assignment to data descriptor attribute `nickname` on type `SuperUser` with custom `__set__` method"
|
|
||||||
james.nickname = "Bob"
|
james.nickname = "Bob"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1694,7 +1694,11 @@ class NotSubtype:
|
||||||
def m(self, x: int) -> int:
|
def m(self, x: int) -> int:
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
|
class DefinitelyNotSubtype:
|
||||||
|
m = None
|
||||||
|
|
||||||
static_assert(is_subtype_of(NominalSubtype, P))
|
static_assert(is_subtype_of(NominalSubtype, P))
|
||||||
|
static_assert(not is_subtype_of(DefinitelyNotSubtype, P))
|
||||||
|
|
||||||
# TODO: should pass
|
# TODO: should pass
|
||||||
static_assert(not is_subtype_of(NotSubtype, P)) # error: [static-assert-error]
|
static_assert(not is_subtype_of(NotSubtype, P)) # error: [static-assert-error]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: descriptor_protocol.md - Descriptor protocol - Special descriptors - Properties with no setters
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/descriptor_protocol.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | class DontAssignToMe:
|
||||||
|
2 | @property
|
||||||
|
3 | def immutable(self): ...
|
||||||
|
4 |
|
||||||
|
5 | # error: [invalid-assignment]
|
||||||
|
6 | DontAssignToMe().immutable = "the properties, they are a-changing"
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-assignment]: Cannot assign to read-only property `immutable` on object of type `DontAssignToMe`
|
||||||
|
--> src/mdtest_snippet.py:3:9
|
||||||
|
|
|
||||||
|
1 | class DontAssignToMe:
|
||||||
|
2 | @property
|
||||||
|
3 | def immutable(self): ...
|
||||||
|
| --------- Property `DontAssignToMe.immutable` defined here with no setter
|
||||||
|
4 |
|
||||||
|
5 | # error: [invalid-assignment]
|
||||||
|
6 | DontAssignToMe().immutable = "the properties, they are a-changing"
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ Attempted assignment to `DontAssignToMe.immutable` here
|
||||||
|
|
|
||||||
|
info: rule `invalid-assignment` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -30,6 +30,18 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/function/return_type.md
|
||||||
16 |
|
16 |
|
||||||
17 | # error: [invalid-return-type]
|
17 | # error: [invalid-return-type]
|
||||||
18 | def m(x: T) -> T: ...
|
18 | def m(x: T) -> T: ...
|
||||||
|
19 |
|
||||||
|
20 | class A[T]: ...
|
||||||
|
21 |
|
||||||
|
22 | def f() -> A[int]:
|
||||||
|
23 | class A[T]: ...
|
||||||
|
24 | return A[int]() # error: [invalid-return-type]
|
||||||
|
25 |
|
||||||
|
26 | class B: ...
|
||||||
|
27 |
|
||||||
|
28 | def g() -> B:
|
||||||
|
29 | class B: ...
|
||||||
|
30 | return B() # error: [invalid-return-type]
|
||||||
```
|
```
|
||||||
|
|
||||||
# Diagnostics
|
# Diagnostics
|
||||||
|
|
@ -91,9 +103,45 @@ error[invalid-return-type]: Function always implicitly returns `None`, which is
|
||||||
17 | # error: [invalid-return-type]
|
17 | # error: [invalid-return-type]
|
||||||
18 | def m(x: T) -> T: ...
|
18 | def m(x: T) -> T: ...
|
||||||
| ^
|
| ^
|
||||||
|
19 |
|
||||||
|
20 | class A[T]: ...
|
||||||
|
|
|
|
||||||
info: Consider changing the return annotation to `-> None` or adding a `return` statement
|
info: Consider changing the return annotation to `-> None` or adding a `return` statement
|
||||||
info: Only functions in stub files, methods on protocol classes, or methods with `@abstractmethod` are permitted to have empty bodies
|
info: Only functions in stub files, methods on protocol classes, or methods with `@abstractmethod` are permitted to have empty bodies
|
||||||
info: rule `invalid-return-type` is enabled by default
|
info: rule `invalid-return-type` is enabled by default
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-return-type]: Return type does not match returned value
|
||||||
|
--> src/mdtest_snippet.py:22:12
|
||||||
|
|
|
||||||
|
20 | class A[T]: ...
|
||||||
|
21 |
|
||||||
|
22 | def f() -> A[int]:
|
||||||
|
| ------ Expected `mdtest_snippet.A[int]` because of return type
|
||||||
|
23 | class A[T]: ...
|
||||||
|
24 | return A[int]() # error: [invalid-return-type]
|
||||||
|
| ^^^^^^^^ expected `mdtest_snippet.A[int]`, found `mdtest_snippet.<locals of function 'f'>.A[int]`
|
||||||
|
25 |
|
||||||
|
26 | class B: ...
|
||||||
|
|
|
||||||
|
info: rule `invalid-return-type` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-return-type]: Return type does not match returned value
|
||||||
|
--> src/mdtest_snippet.py:28:12
|
||||||
|
|
|
||||||
|
26 | class B: ...
|
||||||
|
27 |
|
||||||
|
28 | def g() -> B:
|
||||||
|
| - Expected `mdtest_snippet.B` because of return type
|
||||||
|
29 | class B: ...
|
||||||
|
30 | return B() # error: [invalid-return-type]
|
||||||
|
| ^^^ expected `mdtest_snippet.B`, found `mdtest_snippet.<locals of function 'g'>.B`
|
||||||
|
|
|
||||||
|
info: rule `invalid-return-type` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ use crate::suppression::check_suppressions;
|
||||||
use crate::types::call::{Binding, Bindings, CallArguments, CallableBinding};
|
use crate::types::call::{Binding, Bindings, CallArguments, CallableBinding};
|
||||||
pub(crate) use crate::types::class_base::ClassBase;
|
pub(crate) use crate::types::class_base::ClassBase;
|
||||||
use crate::types::constraints::{
|
use crate::types::constraints::{
|
||||||
Constraints, IteratorConstraintsExtension, OptionConstraintsExtension,
|
ConstraintSet, Constraints, IteratorConstraintsExtension, OptionConstraintsExtension,
|
||||||
};
|
};
|
||||||
use crate::types::context::{LintDiagnosticGuard, LintDiagnosticGuardBuilder};
|
use crate::types::context::{LintDiagnosticGuard, LintDiagnosticGuardBuilder};
|
||||||
use crate::types::diagnostic::{INVALID_AWAIT, INVALID_TYPE_FORM, UNSUPPORTED_BOOL_CONVERSION};
|
use crate::types::diagnostic::{INVALID_AWAIT, INVALID_TYPE_FORM, UNSUPPORTED_BOOL_CONVERSION};
|
||||||
|
|
@ -298,7 +298,7 @@ pub(crate) enum AttributeAssignmentError<'db> {
|
||||||
CannotAssignToInstanceAttr,
|
CannotAssignToInstanceAttr,
|
||||||
CannotAssignToFinal,
|
CannotAssignToFinal,
|
||||||
CannotAssignToUnresolved,
|
CannotAssignToUnresolved,
|
||||||
ReadOnlyProperty,
|
ReadOnlyProperty(Option<PropertyInstanceType<'db>>),
|
||||||
FailToSet,
|
FailToSet,
|
||||||
FailToSetAttr,
|
FailToSetAttr,
|
||||||
SetAttrReturnsNeverOrNoReturn,
|
SetAttrReturnsNeverOrNoReturn,
|
||||||
|
|
@ -1428,7 +1428,8 @@ impl<'db> Type<'db> {
|
||||||
/// intersection simplification dependent on the order in which elements are added), so we do
|
/// intersection simplification dependent on the order in which elements are added), so we do
|
||||||
/// not use this more general definition of subtyping.
|
/// not use this more general definition of subtyping.
|
||||||
pub(crate) fn is_subtype_of(self, db: &'db dyn Db, target: Type<'db>) -> bool {
|
pub(crate) fn is_subtype_of(self, db: &'db dyn Db, target: Type<'db>) -> bool {
|
||||||
self.when_subtype_of(db, target)
|
self.when_subtype_of::<ConstraintSet>(db, target)
|
||||||
|
.is_always_satisfied(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn when_subtype_of<C: Constraints<'db>>(self, db: &'db dyn Db, target: Type<'db>) -> C {
|
fn when_subtype_of<C: Constraints<'db>>(self, db: &'db dyn Db, target: Type<'db>) -> C {
|
||||||
|
|
@ -1439,7 +1440,8 @@ impl<'db> Type<'db> {
|
||||||
///
|
///
|
||||||
/// [assignable to]: https://typing.python.org/en/latest/spec/concepts.html#the-assignable-to-or-consistent-subtyping-relation
|
/// [assignable to]: https://typing.python.org/en/latest/spec/concepts.html#the-assignable-to-or-consistent-subtyping-relation
|
||||||
pub(crate) fn is_assignable_to(self, db: &'db dyn Db, target: Type<'db>) -> bool {
|
pub(crate) fn is_assignable_to(self, db: &'db dyn Db, target: Type<'db>) -> bool {
|
||||||
self.when_assignable_to(db, target)
|
self.when_assignable_to::<ConstraintSet>(db, target)
|
||||||
|
.is_always_satisfied(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn when_assignable_to<C: Constraints<'db>>(self, db: &'db dyn Db, target: Type<'db>) -> C {
|
fn when_assignable_to<C: Constraints<'db>>(self, db: &'db dyn Db, target: Type<'db>) -> C {
|
||||||
|
|
@ -1917,7 +1919,8 @@ impl<'db> Type<'db> {
|
||||||
///
|
///
|
||||||
/// [equivalent to]: https://typing.python.org/en/latest/spec/glossary.html#term-equivalent
|
/// [equivalent to]: https://typing.python.org/en/latest/spec/glossary.html#term-equivalent
|
||||||
pub(crate) fn is_equivalent_to(self, db: &'db dyn Db, other: Type<'db>) -> bool {
|
pub(crate) fn is_equivalent_to(self, db: &'db dyn Db, other: Type<'db>) -> bool {
|
||||||
self.when_equivalent_to(db, other)
|
self.when_equivalent_to::<ConstraintSet>(db, other)
|
||||||
|
.is_always_satisfied(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn when_equivalent_to<C: Constraints<'db>>(self, db: &'db dyn Db, other: Type<'db>) -> C {
|
fn when_equivalent_to<C: Constraints<'db>>(self, db: &'db dyn Db, other: Type<'db>) -> C {
|
||||||
|
|
@ -2017,7 +2020,8 @@ impl<'db> Type<'db> {
|
||||||
/// Note: This function aims to have no false positives, but might return
|
/// Note: This function aims to have no false positives, but might return
|
||||||
/// wrong `false` answers in some cases.
|
/// wrong `false` answers in some cases.
|
||||||
pub(crate) fn is_disjoint_from(self, db: &'db dyn Db, other: Type<'db>) -> bool {
|
pub(crate) fn is_disjoint_from(self, db: &'db dyn Db, other: Type<'db>) -> bool {
|
||||||
self.when_disjoint_from(db, other)
|
self.when_disjoint_from::<ConstraintSet>(db, other)
|
||||||
|
.is_always_satisfied(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn when_disjoint_from<C: Constraints<'db>>(self, db: &'db dyn Db, other: Type<'db>) -> C {
|
fn when_disjoint_from<C: Constraints<'db>>(self, db: &'db dyn Db, other: Type<'db>) -> C {
|
||||||
|
|
@ -5058,7 +5062,7 @@ impl<'db> Type<'db> {
|
||||||
Err(if !member_exists {
|
Err(if !member_exists {
|
||||||
AttributeAssignmentError::CannotAssignToUnresolved
|
AttributeAssignmentError::CannotAssignToUnresolved
|
||||||
} else if is_setattr_synthesized {
|
} else if is_setattr_synthesized {
|
||||||
AttributeAssignmentError::ReadOnlyProperty
|
AttributeAssignmentError::ReadOnlyProperty(None)
|
||||||
} else {
|
} else {
|
||||||
AttributeAssignmentError::SetAttrReturnsNeverOrNoReturn
|
AttributeAssignmentError::SetAttrReturnsNeverOrNoReturn
|
||||||
})
|
})
|
||||||
|
|
@ -5092,19 +5096,23 @@ impl<'db> Type<'db> {
|
||||||
if let Place::Type(meta_dunder_set, _) =
|
if let Place::Type(meta_dunder_set, _) =
|
||||||
meta_attr_ty.class_member(db, "__set__".into()).place
|
meta_attr_ty.class_member(db, "__set__".into()).place
|
||||||
{
|
{
|
||||||
let successful_call = meta_dunder_set
|
let dunder_set_result = meta_dunder_set.try_call(
|
||||||
.try_call(
|
db,
|
||||||
db,
|
&CallArguments::positional([meta_attr_ty, self, value_ty]),
|
||||||
&CallArguments::positional([
|
);
|
||||||
meta_attr_ty,
|
|
||||||
self,
|
|
||||||
value_ty,
|
|
||||||
]),
|
|
||||||
)
|
|
||||||
.is_ok();
|
|
||||||
|
|
||||||
if !successful_call {
|
if let Err(dunder_set_error) = dunder_set_result {
|
||||||
results.insert(AttributeAssignmentError::FailToSet);
|
results.insert(
|
||||||
|
if let Some(property) = dunder_set_error
|
||||||
|
.as_attempt_to_set_property_with_no_setter()
|
||||||
|
{
|
||||||
|
AttributeAssignmentError::ReadOnlyProperty(Some(
|
||||||
|
property,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
AttributeAssignmentError::FailToSet
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
results.insert_if_error(ensure_assignable_to(meta_attr_ty));
|
results.insert_if_error(ensure_assignable_to(meta_attr_ty));
|
||||||
|
|
@ -5178,15 +5186,21 @@ impl<'db> Type<'db> {
|
||||||
if let Place::Type(meta_dunder_set, _) =
|
if let Place::Type(meta_dunder_set, _) =
|
||||||
meta_attr_ty.class_member(db, "__set__".into()).place
|
meta_attr_ty.class_member(db, "__set__".into()).place
|
||||||
{
|
{
|
||||||
let successful_call = meta_dunder_set
|
let dunder_set_result = meta_dunder_set.try_call(
|
||||||
.try_call(
|
db,
|
||||||
db,
|
&CallArguments::positional([meta_attr_ty, self, value_ty]),
|
||||||
&CallArguments::positional([meta_attr_ty, self, value_ty]),
|
);
|
||||||
)
|
|
||||||
.is_ok();
|
|
||||||
|
|
||||||
if !successful_call {
|
if let Err(dunder_set_error) = dunder_set_result {
|
||||||
results.insert(AttributeAssignmentError::FailToSet);
|
results.insert(
|
||||||
|
if let Some(property) =
|
||||||
|
dunder_set_error.as_attempt_to_set_property_with_no_setter()
|
||||||
|
{
|
||||||
|
AttributeAssignmentError::ReadOnlyProperty(Some(property))
|
||||||
|
} else {
|
||||||
|
AttributeAssignmentError::FailToSet
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
results.insert_if_error(ensure_assignable_to(meta_attr_ty));
|
results.insert_if_error(ensure_assignable_to(meta_attr_ty));
|
||||||
|
|
@ -5278,7 +5292,7 @@ impl<'db> Type<'db> {
|
||||||
argument_types: &CallArguments<'_, 'db>,
|
argument_types: &CallArguments<'_, 'db>,
|
||||||
) -> Result<Bindings<'db>, CallError<'db>> {
|
) -> Result<Bindings<'db>, CallError<'db>> {
|
||||||
self.bindings(db)
|
self.bindings(db)
|
||||||
.match_parameters(argument_types)
|
.match_parameters(db, argument_types)
|
||||||
.check_types(db, argument_types)
|
.check_types(db, argument_types)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5327,7 +5341,7 @@ impl<'db> Type<'db> {
|
||||||
Place::Type(dunder_callable, boundness) => {
|
Place::Type(dunder_callable, boundness) => {
|
||||||
let bindings = dunder_callable
|
let bindings = dunder_callable
|
||||||
.bindings(db)
|
.bindings(db)
|
||||||
.match_parameters(argument_types)
|
.match_parameters(db, argument_types)
|
||||||
.check_types(db, argument_types)?;
|
.check_types(db, argument_types)?;
|
||||||
if boundness == Boundness::PossiblyUnbound {
|
if boundness == Boundness::PossiblyUnbound {
|
||||||
return Err(CallDunderError::PossiblyUnbound(Box::new(bindings)));
|
return Err(CallDunderError::PossiblyUnbound(Box::new(bindings)));
|
||||||
|
|
@ -10140,6 +10154,16 @@ pub(super) fn walk_intersection_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> IntersectionType<'db> {
|
impl<'db> IntersectionType<'db> {
|
||||||
|
pub(crate) fn from_elements<I, T>(db: &'db dyn Db, elements: I) -> Type<'db>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = T>,
|
||||||
|
T: Into<Type<'db>>,
|
||||||
|
{
|
||||||
|
IntersectionBuilder::new(db)
|
||||||
|
.positive_elements(elements)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
/// Return a new `IntersectionType` instance with the positive and negative types sorted
|
/// Return a new `IntersectionType` instance with the positive and negative types sorted
|
||||||
/// according to a canonical ordering, and other normalizations applied to each element as applicable.
|
/// according to a canonical ordering, and other normalizations applied to each element as applicable.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use super::context::InferContext;
|
use super::context::InferContext;
|
||||||
use super::{Signature, Type};
|
use super::{Signature, Type};
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
|
use crate::types::PropertyInstanceType;
|
||||||
|
use crate::types::call::bind::BindingError;
|
||||||
|
|
||||||
mod arguments;
|
mod arguments;
|
||||||
pub(crate) mod bind;
|
pub(crate) mod bind;
|
||||||
|
|
@ -14,6 +16,26 @@ pub(super) use bind::{Binding, Bindings, CallableBinding, MatchedArgument};
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct CallError<'db>(pub(crate) CallErrorKind, pub(crate) Box<Bindings<'db>>);
|
pub(crate) struct CallError<'db>(pub(crate) CallErrorKind, pub(crate) Box<Bindings<'db>>);
|
||||||
|
|
||||||
|
impl<'db> CallError<'db> {
|
||||||
|
/// Returns `Some(property)` if the call error was caused by an attempt to set a property
|
||||||
|
/// that has no setter, and `None` otherwise.
|
||||||
|
pub(crate) fn as_attempt_to_set_property_with_no_setter(
|
||||||
|
&self,
|
||||||
|
) -> Option<PropertyInstanceType<'db>> {
|
||||||
|
if self.0 != CallErrorKind::BindingError {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.1
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.flat_map(bind::Binding::errors)
|
||||||
|
.find_map(|error| match error {
|
||||||
|
BindingError::PropertyHasNoSetter(property) => Some(*property),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The reason why calling a type failed.
|
/// The reason why calling a type failed.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub(crate) enum CallErrorKind {
|
pub(crate) enum CallErrorKind {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use std::borrow::Cow;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::{Either, Itertools};
|
||||||
use ruff_db::parsed::parsed_module;
|
use ruff_db::parsed::parsed_module;
|
||||||
use smallvec::{SmallVec, smallvec, smallvec_inline};
|
use smallvec::{SmallVec, smallvec, smallvec_inline};
|
||||||
|
|
||||||
|
|
@ -17,6 +17,7 @@ use crate::db::Db;
|
||||||
use crate::dunder_all::dunder_all_names;
|
use crate::dunder_all::dunder_all_names;
|
||||||
use crate::place::{Boundness, Place};
|
use crate::place::{Boundness, Place};
|
||||||
use crate::types::call::arguments::{Expansion, is_expandable_type};
|
use crate::types::call::arguments::{Expansion, is_expandable_type};
|
||||||
|
use crate::types::constraints::{ConstraintSet, Constraints};
|
||||||
use crate::types::diagnostic::{
|
use crate::types::diagnostic::{
|
||||||
CALL_NON_CALLABLE, CONFLICTING_ARGUMENT_FORMS, INVALID_ARGUMENT_TYPE, MISSING_ARGUMENT,
|
CALL_NON_CALLABLE, CONFLICTING_ARGUMENT_FORMS, INVALID_ARGUMENT_TYPE, MISSING_ARGUMENT,
|
||||||
NO_MATCHING_OVERLOAD, PARAMETER_ALREADY_ASSIGNED, TOO_MANY_POSITIONAL_ARGUMENTS,
|
NO_MATCHING_OVERLOAD, PARAMETER_ALREADY_ASSIGNED, TOO_MANY_POSITIONAL_ARGUMENTS,
|
||||||
|
|
@ -100,11 +101,15 @@ impl<'db> Bindings<'db> {
|
||||||
///
|
///
|
||||||
/// Once you have argument types available, you can call [`check_types`][Self::check_types] to
|
/// Once you have argument types available, you can call [`check_types`][Self::check_types] to
|
||||||
/// verify that each argument type is assignable to the corresponding parameter type.
|
/// verify that each argument type is assignable to the corresponding parameter type.
|
||||||
pub(crate) fn match_parameters(mut self, arguments: &CallArguments<'_, 'db>) -> Self {
|
pub(crate) fn match_parameters(
|
||||||
|
mut self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
arguments: &CallArguments<'_, 'db>,
|
||||||
|
) -> Self {
|
||||||
let mut argument_forms = vec![None; arguments.len()];
|
let mut argument_forms = vec![None; arguments.len()];
|
||||||
let mut conflicting_forms = vec![false; arguments.len()];
|
let mut conflicting_forms = vec![false; arguments.len()];
|
||||||
for binding in &mut self.elements {
|
for binding in &mut self.elements {
|
||||||
binding.match_parameters(arguments, &mut argument_forms, &mut conflicting_forms);
|
binding.match_parameters(db, arguments, &mut argument_forms, &mut conflicting_forms);
|
||||||
}
|
}
|
||||||
self.argument_forms = argument_forms.into();
|
self.argument_forms = argument_forms.into();
|
||||||
self.conflicting_forms = conflicting_forms.into();
|
self.conflicting_forms = conflicting_forms.into();
|
||||||
|
|
@ -421,9 +426,9 @@ impl<'db> Bindings<'db> {
|
||||||
overload.set_return_type(Type::unknown());
|
overload.set_return_type(Type::unknown());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
overload.errors.push(BindingError::InternalCallError(
|
overload
|
||||||
"property has no getter",
|
.errors
|
||||||
));
|
.push(BindingError::PropertyHasNoSetter(*property));
|
||||||
overload.set_return_type(Type::Never);
|
overload.set_return_type(Type::Never);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -477,9 +482,9 @@ impl<'db> Bindings<'db> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
overload.errors.push(BindingError::InternalCallError(
|
overload
|
||||||
"property has no setter",
|
.errors
|
||||||
));
|
.push(BindingError::PropertyHasNoSetter(*property));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -495,9 +500,9 @@ impl<'db> Bindings<'db> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
overload.errors.push(BindingError::InternalCallError(
|
overload
|
||||||
"property has no setter",
|
.errors
|
||||||
));
|
.push(BindingError::PropertyHasNoSetter(property));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1242,6 +1247,7 @@ impl<'db> CallableBinding<'db> {
|
||||||
|
|
||||||
fn match_parameters(
|
fn match_parameters(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
db: &'db dyn Db,
|
||||||
arguments: &CallArguments<'_, 'db>,
|
arguments: &CallArguments<'_, 'db>,
|
||||||
argument_forms: &mut [Option<ParameterForm>],
|
argument_forms: &mut [Option<ParameterForm>],
|
||||||
conflicting_forms: &mut [bool],
|
conflicting_forms: &mut [bool],
|
||||||
|
|
@ -1251,7 +1257,7 @@ impl<'db> CallableBinding<'db> {
|
||||||
let arguments = arguments.with_self(self.bound_type);
|
let arguments = arguments.with_self(self.bound_type);
|
||||||
|
|
||||||
for overload in &mut self.overloads {
|
for overload in &mut self.overloads {
|
||||||
overload.match_parameters(arguments.as_ref(), argument_forms, conflicting_forms);
|
overload.match_parameters(db, arguments.as_ref(), argument_forms, conflicting_forms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1902,7 +1908,7 @@ struct ArgumentMatcher<'a, 'db> {
|
||||||
conflicting_forms: &'a mut [bool],
|
conflicting_forms: &'a mut [bool],
|
||||||
errors: &'a mut Vec<BindingError<'db>>,
|
errors: &'a mut Vec<BindingError<'db>>,
|
||||||
|
|
||||||
argument_matches: Vec<MatchedArgument>,
|
argument_matches: Vec<MatchedArgument<'db>>,
|
||||||
parameter_matched: Vec<bool>,
|
parameter_matched: Vec<bool>,
|
||||||
next_positional: usize,
|
next_positional: usize,
|
||||||
first_excess_positional: Option<usize>,
|
first_excess_positional: Option<usize>,
|
||||||
|
|
@ -1946,6 +1952,7 @@ impl<'a, 'db> ArgumentMatcher<'a, 'db> {
|
||||||
&mut self,
|
&mut self,
|
||||||
argument_index: usize,
|
argument_index: usize,
|
||||||
argument: Argument<'a>,
|
argument: Argument<'a>,
|
||||||
|
argument_type: Option<Type<'db>>,
|
||||||
parameter_index: usize,
|
parameter_index: usize,
|
||||||
parameter: &Parameter<'db>,
|
parameter: &Parameter<'db>,
|
||||||
positional: bool,
|
positional: bool,
|
||||||
|
|
@ -1969,6 +1976,7 @@ impl<'a, 'db> ArgumentMatcher<'a, 'db> {
|
||||||
}
|
}
|
||||||
let matched_argument = &mut self.argument_matches[argument_index];
|
let matched_argument = &mut self.argument_matches[argument_index];
|
||||||
matched_argument.parameters.push(parameter_index);
|
matched_argument.parameters.push(parameter_index);
|
||||||
|
matched_argument.types.push(argument_type);
|
||||||
matched_argument.matched = true;
|
matched_argument.matched = true;
|
||||||
self.parameter_matched[parameter_index] = true;
|
self.parameter_matched[parameter_index] = true;
|
||||||
}
|
}
|
||||||
|
|
@ -1977,6 +1985,7 @@ impl<'a, 'db> ArgumentMatcher<'a, 'db> {
|
||||||
&mut self,
|
&mut self,
|
||||||
argument_index: usize,
|
argument_index: usize,
|
||||||
argument: Argument<'a>,
|
argument: Argument<'a>,
|
||||||
|
argument_type: Option<Type<'db>>,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
if matches!(argument, Argument::Synthetic) {
|
if matches!(argument, Argument::Synthetic) {
|
||||||
self.num_synthetic_args += 1;
|
self.num_synthetic_args += 1;
|
||||||
|
|
@ -1995,6 +2004,7 @@ impl<'a, 'db> ArgumentMatcher<'a, 'db> {
|
||||||
self.assign_argument(
|
self.assign_argument(
|
||||||
argument_index,
|
argument_index,
|
||||||
argument,
|
argument,
|
||||||
|
argument_type,
|
||||||
parameter_index,
|
parameter_index,
|
||||||
parameter,
|
parameter,
|
||||||
!parameter.is_variadic(),
|
!parameter.is_variadic(),
|
||||||
|
|
@ -2019,20 +2029,35 @@ impl<'a, 'db> ArgumentMatcher<'a, 'db> {
|
||||||
});
|
});
|
||||||
return Err(());
|
return Err(());
|
||||||
};
|
};
|
||||||
self.assign_argument(argument_index, argument, parameter_index, parameter, false);
|
self.assign_argument(
|
||||||
|
argument_index,
|
||||||
|
argument,
|
||||||
|
None,
|
||||||
|
parameter_index,
|
||||||
|
parameter,
|
||||||
|
false,
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_variadic(
|
fn match_variadic(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
db: &'db dyn Db,
|
||||||
argument_index: usize,
|
argument_index: usize,
|
||||||
argument: Argument<'a>,
|
argument: Argument<'a>,
|
||||||
|
argument_type: Option<Type<'db>>,
|
||||||
length: TupleLength,
|
length: TupleLength,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
|
let tuple = argument_type.map(|ty| ty.iterate(db));
|
||||||
|
let mut argument_types = match tuple.as_ref() {
|
||||||
|
Some(tuple) => Either::Left(tuple.all_elements().copied()),
|
||||||
|
None => Either::Right(std::iter::empty()),
|
||||||
|
};
|
||||||
|
|
||||||
// We must be able to match up the fixed-length portion of the argument with positional
|
// We must be able to match up the fixed-length portion of the argument with positional
|
||||||
// parameters, so we pass on any errors that occur.
|
// parameters, so we pass on any errors that occur.
|
||||||
for _ in 0..length.minimum() {
|
for _ in 0..length.minimum() {
|
||||||
self.match_positional(argument_index, argument)?;
|
self.match_positional(argument_index, argument, argument_types.next())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the tuple is variable-length, we assume that it will soak up all remaining positional
|
// If the tuple is variable-length, we assume that it will soak up all remaining positional
|
||||||
|
|
@ -2043,14 +2068,14 @@ impl<'a, 'db> ArgumentMatcher<'a, 'db> {
|
||||||
.get_positional(self.next_positional)
|
.get_positional(self.next_positional)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
self.match_positional(argument_index, argument)?;
|
self.match_positional(argument_index, argument, argument_types.next())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self) -> Box<[MatchedArgument]> {
|
fn finish(self) -> Box<[MatchedArgument<'db>]> {
|
||||||
if let Some(first_excess_argument_index) = self.first_excess_positional {
|
if let Some(first_excess_argument_index) = self.first_excess_positional {
|
||||||
self.errors.push(BindingError::TooManyPositionalArguments {
|
self.errors.push(BindingError::TooManyPositionalArguments {
|
||||||
first_excess_argument_index: self.get_argument_index(first_excess_argument_index),
|
first_excess_argument_index: self.get_argument_index(first_excess_argument_index),
|
||||||
|
|
@ -2087,7 +2112,7 @@ struct ArgumentTypeChecker<'a, 'db> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
signature: &'a Signature<'db>,
|
signature: &'a Signature<'db>,
|
||||||
arguments: &'a CallArguments<'a, 'db>,
|
arguments: &'a CallArguments<'a, 'db>,
|
||||||
argument_matches: &'a [MatchedArgument],
|
argument_matches: &'a [MatchedArgument<'db>],
|
||||||
parameter_tys: &'a mut [Option<Type<'db>>],
|
parameter_tys: &'a mut [Option<Type<'db>>],
|
||||||
errors: &'a mut Vec<BindingError<'db>>,
|
errors: &'a mut Vec<BindingError<'db>>,
|
||||||
|
|
||||||
|
|
@ -2100,7 +2125,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
signature: &'a Signature<'db>,
|
signature: &'a Signature<'db>,
|
||||||
arguments: &'a CallArguments<'a, 'db>,
|
arguments: &'a CallArguments<'a, 'db>,
|
||||||
argument_matches: &'a [MatchedArgument],
|
argument_matches: &'a [MatchedArgument<'db>],
|
||||||
parameter_tys: &'a mut [Option<Type<'db>>],
|
parameter_tys: &'a mut [Option<Type<'db>>],
|
||||||
errors: &'a mut Vec<BindingError<'db>>,
|
errors: &'a mut Vec<BindingError<'db>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -2155,12 +2180,17 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
|
||||||
for (argument_index, adjusted_argument_index, _, argument_type) in
|
for (argument_index, adjusted_argument_index, _, argument_type) in
|
||||||
self.enumerate_argument_types()
|
self.enumerate_argument_types()
|
||||||
{
|
{
|
||||||
for parameter_index in &self.argument_matches[argument_index].parameters {
|
for (parameter_index, variadic_argument_type) in
|
||||||
let parameter = ¶meters[*parameter_index];
|
self.argument_matches[argument_index].iter()
|
||||||
|
{
|
||||||
|
let parameter = ¶meters[parameter_index];
|
||||||
let Some(expected_type) = parameter.annotated_type() else {
|
let Some(expected_type) = parameter.annotated_type() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if let Err(error) = builder.infer(expected_type, argument_type) {
|
if let Err(error) = builder.infer(
|
||||||
|
expected_type,
|
||||||
|
variadic_argument_type.unwrap_or(argument_type),
|
||||||
|
) {
|
||||||
self.errors.push(BindingError::SpecializationError {
|
self.errors.push(BindingError::SpecializationError {
|
||||||
error,
|
error,
|
||||||
argument_index: adjusted_argument_index,
|
argument_index: adjusted_argument_index,
|
||||||
|
|
@ -2198,7 +2228,16 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
|
||||||
argument_type.apply_specialization(self.db, inherited_specialization);
|
argument_type.apply_specialization(self.db, inherited_specialization);
|
||||||
expected_ty = expected_ty.apply_specialization(self.db, inherited_specialization);
|
expected_ty = expected_ty.apply_specialization(self.db, inherited_specialization);
|
||||||
}
|
}
|
||||||
if !argument_type.is_assignable_to(self.db, expected_ty) {
|
// This is one of the few places where we want to check if there's _any_ specialization
|
||||||
|
// where assignability holds; normally we want to check that assignability holds for
|
||||||
|
// _all_ specializations.
|
||||||
|
// TODO: Soon we will go further, and build the actual specializations from the
|
||||||
|
// constraint set that we get from this assignability check, instead of inferring and
|
||||||
|
// building them in an earlier separate step.
|
||||||
|
if argument_type
|
||||||
|
.when_assignable_to::<ConstraintSet>(self.db, expected_ty)
|
||||||
|
.is_never_satisfied(self.db)
|
||||||
|
{
|
||||||
let positional = matches!(argument, Argument::Positional | Argument::Synthetic)
|
let positional = matches!(argument, Argument::Positional | Argument::Synthetic)
|
||||||
&& !parameter.is_variadic();
|
&& !parameter.is_variadic();
|
||||||
self.errors.push(BindingError::InvalidArgumentType {
|
self.errors.push(BindingError::InvalidArgumentType {
|
||||||
|
|
@ -2295,7 +2334,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
|
||||||
/// Information about which parameter(s) an argument was matched against. This is tracked
|
/// Information about which parameter(s) an argument was matched against. This is tracked
|
||||||
/// separately for each overload.
|
/// separately for each overload.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct MatchedArgument {
|
pub struct MatchedArgument<'db> {
|
||||||
/// The index of the parameter(s) that an argument was matched against. A splatted argument
|
/// The index of the parameter(s) that an argument was matched against. A splatted argument
|
||||||
/// might be matched against multiple parameters.
|
/// might be matched against multiple parameters.
|
||||||
pub parameters: SmallVec<[usize; 1]>,
|
pub parameters: SmallVec<[usize; 1]>,
|
||||||
|
|
@ -2304,6 +2343,33 @@ pub struct MatchedArgument {
|
||||||
/// elements must have been successfully matched. (That means that this can be `false` while
|
/// elements must have been successfully matched. (That means that this can be `false` while
|
||||||
/// the `parameters` field is non-empty.)
|
/// the `parameters` field is non-empty.)
|
||||||
pub matched: bool,
|
pub matched: bool,
|
||||||
|
|
||||||
|
/// The types of a variadic argument when it's unpacked.
|
||||||
|
///
|
||||||
|
/// The length of this vector is always the same as the `parameters` vector i.e., these are the
|
||||||
|
/// types assigned to each matched parameter. This isn't necessarily the same as the number of
|
||||||
|
/// types in the argument type which might not be a fixed-length iterable.
|
||||||
|
///
|
||||||
|
/// Another thing to note is that the way this is populated means that for any other argument
|
||||||
|
/// kind (synthetic, positional, keyword, keyword-variadic), this will be a single-element
|
||||||
|
/// vector containing `None`, since we don't know the type of the argument when this is
|
||||||
|
/// constructed. So, this field is populated only for variadic arguments.
|
||||||
|
///
|
||||||
|
/// For example, given a `*args` whose type is `tuple[A, B, C]` and the following parameters:
|
||||||
|
/// - `(x, *args)`: the `types` field will only have two elements (`B`, `C`) since `A` has been
|
||||||
|
/// matched with `x`.
|
||||||
|
/// - `(*args)`: the `types` field will have all the three elements (`A`, `B`, `C`)
|
||||||
|
types: SmallVec<[Option<Type<'db>>; 1]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'db> MatchedArgument<'db> {
|
||||||
|
/// Returns an iterator over the parameter indices and the corresponding argument type.
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = (usize, Option<Type<'db>>)> + '_ {
|
||||||
|
self.parameters
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(self.types.iter().copied())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Binding information for one of the overloads of a callable.
|
/// Binding information for one of the overloads of a callable.
|
||||||
|
|
@ -2331,7 +2397,7 @@ pub(crate) struct Binding<'db> {
|
||||||
|
|
||||||
/// Information about which parameter(s) each argument was matched with, in argument source
|
/// Information about which parameter(s) each argument was matched with, in argument source
|
||||||
/// order.
|
/// order.
|
||||||
argument_matches: Box<[MatchedArgument]>,
|
argument_matches: Box<[MatchedArgument<'db>]>,
|
||||||
|
|
||||||
/// Bound types for parameters, in parameter source order, or `None` if no argument was matched
|
/// Bound types for parameters, in parameter source order, or `None` if no argument was matched
|
||||||
/// to that parameter.
|
/// to that parameter.
|
||||||
|
|
@ -2364,6 +2430,7 @@ impl<'db> Binding<'db> {
|
||||||
|
|
||||||
pub(crate) fn match_parameters(
|
pub(crate) fn match_parameters(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
db: &'db dyn Db,
|
||||||
arguments: &CallArguments<'_, 'db>,
|
arguments: &CallArguments<'_, 'db>,
|
||||||
argument_forms: &mut [Option<ParameterForm>],
|
argument_forms: &mut [Option<ParameterForm>],
|
||||||
conflicting_forms: &mut [bool],
|
conflicting_forms: &mut [bool],
|
||||||
|
|
@ -2376,16 +2443,17 @@ impl<'db> Binding<'db> {
|
||||||
conflicting_forms,
|
conflicting_forms,
|
||||||
&mut self.errors,
|
&mut self.errors,
|
||||||
);
|
);
|
||||||
for (argument_index, (argument, _)) in arguments.iter().enumerate() {
|
for (argument_index, (argument, argument_type)) in arguments.iter().enumerate() {
|
||||||
match argument {
|
match argument {
|
||||||
Argument::Positional | Argument::Synthetic => {
|
Argument::Positional | Argument::Synthetic => {
|
||||||
let _ = matcher.match_positional(argument_index, argument);
|
let _ = matcher.match_positional(argument_index, argument, None);
|
||||||
}
|
}
|
||||||
Argument::Keyword(name) => {
|
Argument::Keyword(name) => {
|
||||||
let _ = matcher.match_keyword(argument_index, argument, name);
|
let _ = matcher.match_keyword(argument_index, argument, name);
|
||||||
}
|
}
|
||||||
Argument::Variadic(length) => {
|
Argument::Variadic(length) => {
|
||||||
let _ = matcher.match_variadic(argument_index, argument, length);
|
let _ =
|
||||||
|
matcher.match_variadic(db, argument_index, argument, argument_type, length);
|
||||||
}
|
}
|
||||||
Argument::Keywords => {
|
Argument::Keywords => {
|
||||||
// TODO
|
// TODO
|
||||||
|
|
@ -2522,9 +2590,13 @@ impl<'db> Binding<'db> {
|
||||||
|
|
||||||
/// Returns a vector where each index corresponds to an argument position,
|
/// Returns a vector where each index corresponds to an argument position,
|
||||||
/// and the value is the parameter index that argument maps to (if any).
|
/// and the value is the parameter index that argument maps to (if any).
|
||||||
pub(crate) fn argument_matches(&self) -> &[MatchedArgument] {
|
pub(crate) fn argument_matches(&self) -> &[MatchedArgument<'db>] {
|
||||||
&self.argument_matches
|
&self.argument_matches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn errors(&self) -> &[BindingError<'db>] {
|
||||||
|
&self.errors
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -2532,7 +2604,7 @@ struct BindingSnapshot<'db> {
|
||||||
return_ty: Type<'db>,
|
return_ty: Type<'db>,
|
||||||
specialization: Option<Specialization<'db>>,
|
specialization: Option<Specialization<'db>>,
|
||||||
inherited_specialization: Option<Specialization<'db>>,
|
inherited_specialization: Option<Specialization<'db>>,
|
||||||
argument_matches: Box<[MatchedArgument]>,
|
argument_matches: Box<[MatchedArgument<'db>]>,
|
||||||
parameter_tys: Box<[Option<Type<'db>>]>,
|
parameter_tys: Box<[Option<Type<'db>>]>,
|
||||||
errors: Vec<BindingError<'db>>,
|
errors: Vec<BindingError<'db>>,
|
||||||
}
|
}
|
||||||
|
|
@ -2743,7 +2815,9 @@ pub(crate) enum BindingError<'db> {
|
||||||
provided_ty: Type<'db>,
|
provided_ty: Type<'db>,
|
||||||
},
|
},
|
||||||
/// One or more required parameters (that is, with no default) is not supplied by any argument.
|
/// One or more required parameters (that is, with no default) is not supplied by any argument.
|
||||||
MissingArguments { parameters: ParameterContexts },
|
MissingArguments {
|
||||||
|
parameters: ParameterContexts,
|
||||||
|
},
|
||||||
/// A call argument can't be matched to any parameter.
|
/// A call argument can't be matched to any parameter.
|
||||||
UnknownArgument {
|
UnknownArgument {
|
||||||
argument_name: ast::name::Name,
|
argument_name: ast::name::Name,
|
||||||
|
|
@ -2765,6 +2839,7 @@ pub(crate) enum BindingError<'db> {
|
||||||
error: SpecializationError<'db>,
|
error: SpecializationError<'db>,
|
||||||
argument_index: Option<usize>,
|
argument_index: Option<usize>,
|
||||||
},
|
},
|
||||||
|
PropertyHasNoSetter(PropertyInstanceType<'db>),
|
||||||
/// The call itself might be well constructed, but an error occurred while evaluating the call.
|
/// The call itself might be well constructed, but an error occurred while evaluating the call.
|
||||||
/// We use this variant to report errors in `property.__get__` and `property.__set__`, which
|
/// We use this variant to report errors in `property.__get__` and `property.__set__`, which
|
||||||
/// can occur when the call to the underlying getter/setter fails.
|
/// can occur when the call to the underlying getter/setter fails.
|
||||||
|
|
@ -3031,6 +3106,17 @@ impl<'db> BindingError<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Self::PropertyHasNoSetter(_) => {
|
||||||
|
BindingError::InternalCallError("property has no setter").report_diagnostic(
|
||||||
|
context,
|
||||||
|
node,
|
||||||
|
callable_ty,
|
||||||
|
callable_description,
|
||||||
|
union_diag,
|
||||||
|
matching_overload,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Self::InternalCallError(reason) => {
|
Self::InternalCallError(reason) => {
|
||||||
let node = Self::get_node(node, None);
|
let node = Self::get_node(node, None);
|
||||||
if let Some(builder) = context.report_lint(&CALL_NON_CALLABLE, node) {
|
if let Some(builder) = context.report_lint(&CALL_NON_CALLABLE, node) {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use crate::semantic_index::{
|
||||||
BindingWithConstraints, DeclarationWithConstraint, SemanticIndex, attribute_declarations,
|
BindingWithConstraints, DeclarationWithConstraint, SemanticIndex, attribute_declarations,
|
||||||
attribute_scopes,
|
attribute_scopes,
|
||||||
};
|
};
|
||||||
use crate::types::constraints::{Constraints, IteratorConstraintsExtension};
|
use crate::types::constraints::{ConstraintSet, Constraints, IteratorConstraintsExtension};
|
||||||
use crate::types::context::InferContext;
|
use crate::types::context::InferContext;
|
||||||
use crate::types::diagnostic::{INVALID_LEGACY_TYPE_VARIABLE, INVALID_TYPE_ALIAS_TYPE};
|
use crate::types::diagnostic::{INVALID_LEGACY_TYPE_VARIABLE, INVALID_TYPE_ALIAS_TYPE};
|
||||||
use crate::types::enums::enum_metadata;
|
use crate::types::enums::enum_metadata;
|
||||||
|
|
@ -552,7 +552,8 @@ impl<'db> ClassType<'db> {
|
||||||
|
|
||||||
/// Return `true` if `other` is present in this class's MRO.
|
/// Return `true` if `other` is present in this class's MRO.
|
||||||
pub(super) fn is_subclass_of(self, db: &'db dyn Db, other: ClassType<'db>) -> bool {
|
pub(super) fn is_subclass_of(self, db: &'db dyn Db, other: ClassType<'db>) -> bool {
|
||||||
self.when_subclass_of(db, other)
|
self.when_subclass_of::<ConstraintSet>(db, other)
|
||||||
|
.is_always_satisfied(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn when_subclass_of<C: Constraints<'db>>(
|
pub(super) fn when_subclass_of<C: Constraints<'db>>(
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -10,7 +10,7 @@ use crate::semantic_index::SemanticIndex;
|
||||||
use crate::semantic_index::definition::Definition;
|
use crate::semantic_index::definition::Definition;
|
||||||
use crate::semantic_index::place::{PlaceTable, ScopedPlaceId};
|
use crate::semantic_index::place::{PlaceTable, ScopedPlaceId};
|
||||||
use crate::suppression::FileSuppressionId;
|
use crate::suppression::FileSuppressionId;
|
||||||
use crate::types::class::{ClassType, DisjointBase, DisjointBaseKind, Field};
|
use crate::types::class::{DisjointBase, DisjointBaseKind, Field};
|
||||||
use crate::types::function::KnownFunction;
|
use crate::types::function::KnownFunction;
|
||||||
use crate::types::string_annotation::{
|
use crate::types::string_annotation::{
|
||||||
BYTE_STRING_TYPE_ANNOTATION, ESCAPE_CHARACTER_IN_FORWARD_ANNOTATION, FSTRING_TYPE_ANNOTATION,
|
BYTE_STRING_TYPE_ANNOTATION, ESCAPE_CHARACTER_IN_FORWARD_ANNOTATION, FSTRING_TYPE_ANNOTATION,
|
||||||
|
|
@ -18,7 +18,8 @@ use crate::types::string_annotation::{
|
||||||
RAW_STRING_TYPE_ANNOTATION,
|
RAW_STRING_TYPE_ANNOTATION,
|
||||||
};
|
};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
DynamicType, LintDiagnosticGuard, Protocol, ProtocolInstanceType, SubclassOfInner, binding_type,
|
DynamicType, LintDiagnosticGuard, PropertyInstanceType, Protocol, ProtocolInstanceType,
|
||||||
|
SubclassOfInner, binding_type,
|
||||||
};
|
};
|
||||||
use crate::types::{SpecialFormType, Type, protocol_class::ProtocolClass};
|
use crate::types::{SpecialFormType, Type, protocol_class::ProtocolClass};
|
||||||
use crate::util::diagnostics::format_enumeration;
|
use crate::util::diagnostics::format_enumeration;
|
||||||
|
|
@ -26,7 +27,7 @@ use crate::{
|
||||||
Db, DisplaySettings, FxIndexMap, FxOrderMap, Module, ModuleName, Program, declare_lint,
|
Db, DisplaySettings, FxIndexMap, FxOrderMap, Module, ModuleName, Program, declare_lint,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ruff_db::diagnostic::{Annotation, Diagnostic, SubDiagnostic, SubDiagnosticSeverity};
|
use ruff_db::diagnostic::{Annotation, Diagnostic, Span, SubDiagnostic, SubDiagnosticSeverity};
|
||||||
use ruff_python_ast::name::Name;
|
use ruff_python_ast::name::Name;
|
||||||
use ruff_python_ast::{self as ast, AnyNodeRef};
|
use ruff_python_ast::{self as ast, AnyNodeRef};
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
@ -1945,18 +1946,8 @@ pub(super) fn report_invalid_assignment(
|
||||||
target_ty: Type,
|
target_ty: Type,
|
||||||
source_ty: Type,
|
source_ty: Type,
|
||||||
) {
|
) {
|
||||||
let mut settings = DisplaySettings::default();
|
let settings =
|
||||||
// Handles the situation where the report naming is confusing, such as class with the same Name,
|
DisplaySettings::from_possibly_ambiguous_type_pair(context.db(), target_ty, source_ty);
|
||||||
// but from different scopes.
|
|
||||||
if let Some(target_class) = type_to_class_literal(target_ty, context.db()) {
|
|
||||||
if let Some(source_class) = type_to_class_literal(source_ty, context.db()) {
|
|
||||||
if target_class != source_class
|
|
||||||
&& target_class.name(context.db()) == source_class.name(context.db())
|
|
||||||
{
|
|
||||||
settings = settings.qualified();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
report_invalid_assignment_with_message(
|
report_invalid_assignment_with_message(
|
||||||
context,
|
context,
|
||||||
|
|
@ -1970,36 +1961,6 @@ pub(super) fn report_invalid_assignment(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: generalize this to a method that takes any two types, walks them recursively, and returns
|
|
||||||
// a set of types with ambiguous names whose display should be qualified. Then we can use this in
|
|
||||||
// any diagnostic that displays two types.
|
|
||||||
fn type_to_class_literal<'db>(ty: Type<'db>, db: &'db dyn crate::Db) -> Option<ClassLiteral<'db>> {
|
|
||||||
match ty {
|
|
||||||
Type::ClassLiteral(class) => Some(class),
|
|
||||||
Type::NominalInstance(instance) => match instance.class(db) {
|
|
||||||
crate::types::class::ClassType::NonGeneric(class) => Some(class),
|
|
||||||
crate::types::class::ClassType::Generic(alias) => Some(alias.origin(db)),
|
|
||||||
},
|
|
||||||
Type::EnumLiteral(enum_literal) => Some(enum_literal.enum_class(db)),
|
|
||||||
Type::GenericAlias(alias) => Some(alias.origin(db)),
|
|
||||||
Type::ProtocolInstance(ProtocolInstanceType {
|
|
||||||
inner: Protocol::FromClass(class),
|
|
||||||
..
|
|
||||||
}) => match class {
|
|
||||||
ClassType::NonGeneric(class) => Some(class),
|
|
||||||
ClassType::Generic(alias) => Some(alias.origin(db)),
|
|
||||||
},
|
|
||||||
Type::TypedDict(typed_dict) => match typed_dict.defining_class() {
|
|
||||||
ClassType::NonGeneric(class) => Some(class),
|
|
||||||
ClassType::Generic(alias) => Some(alias.origin(db)),
|
|
||||||
},
|
|
||||||
Type::SubclassOf(subclass_of) => {
|
|
||||||
type_to_class_literal(Type::from(subclass_of.subclass_of().into_class()?), db)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn report_invalid_attribute_assignment(
|
pub(super) fn report_invalid_attribute_assignment(
|
||||||
context: &InferContext,
|
context: &InferContext,
|
||||||
node: AnyNodeRef,
|
node: AnyNodeRef,
|
||||||
|
|
@ -2019,6 +1980,42 @@ pub(super) fn report_invalid_attribute_assignment(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn report_attempted_write_to_read_only_property<'db>(
|
||||||
|
context: &InferContext<'db, '_>,
|
||||||
|
property: Option<PropertyInstanceType<'db>>,
|
||||||
|
attribute: &str,
|
||||||
|
object_type: Type<'db>,
|
||||||
|
target: &ast::ExprAttribute,
|
||||||
|
) {
|
||||||
|
let Some(builder) = context.report_lint(&INVALID_ASSIGNMENT, target) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let db = context.db();
|
||||||
|
let object_type = object_type.display(db);
|
||||||
|
|
||||||
|
if let Some(file_range) = property
|
||||||
|
.and_then(|property| property.getter(db))
|
||||||
|
.and_then(|getter| getter.definition(db))
|
||||||
|
.and_then(|definition| definition.focus_range(db))
|
||||||
|
{
|
||||||
|
let mut diagnostic = builder.into_diagnostic(format_args!(
|
||||||
|
"Cannot assign to read-only property `{attribute}` on object of type `{object_type}`",
|
||||||
|
));
|
||||||
|
diagnostic.annotate(
|
||||||
|
Annotation::secondary(Span::from(file_range)).message(format_args!(
|
||||||
|
"Property `{object_type}.{attribute}` defined here with no setter"
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
diagnostic.set_primary_message(format_args!(
|
||||||
|
"Attempted assignment to `{object_type}.{attribute}` here"
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
builder.into_diagnostic(format_args!(
|
||||||
|
"Attribute `{attribute}` on object of type `{object_type}` is read-only",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn report_invalid_return_type(
|
pub(super) fn report_invalid_return_type(
|
||||||
context: &InferContext,
|
context: &InferContext,
|
||||||
object_range: impl Ranged,
|
object_range: impl Ranged,
|
||||||
|
|
@ -2030,18 +2027,20 @@ pub(super) fn report_invalid_return_type(
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let settings =
|
||||||
|
DisplaySettings::from_possibly_ambiguous_type_pair(context.db(), expected_ty, actual_ty);
|
||||||
let return_type_span = context.span(return_type_range);
|
let return_type_span = context.span(return_type_range);
|
||||||
|
|
||||||
let mut diag = builder.into_diagnostic("Return type does not match returned value");
|
let mut diag = builder.into_diagnostic("Return type does not match returned value");
|
||||||
diag.set_primary_message(format_args!(
|
diag.set_primary_message(format_args!(
|
||||||
"expected `{expected_ty}`, found `{actual_ty}`",
|
"expected `{expected_ty}`, found `{actual_ty}`",
|
||||||
expected_ty = expected_ty.display(context.db()),
|
expected_ty = expected_ty.display_with(context.db(), settings),
|
||||||
actual_ty = actual_ty.display(context.db()),
|
actual_ty = actual_ty.display_with(context.db(), settings),
|
||||||
));
|
));
|
||||||
diag.annotate(
|
diag.annotate(
|
||||||
Annotation::secondary(return_type_span).message(format_args!(
|
Annotation::secondary(return_type_span).message(format_args!(
|
||||||
"Expected `{expected_ty}` because of return type",
|
"Expected `{expected_ty}` because of return type",
|
||||||
expected_ty = expected_ty.display(context.db()),
|
expected_ty = expected_ty.display_with(context.db(), settings),
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,9 @@ use crate::types::generics::{GenericContext, Specialization};
|
||||||
use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signature};
|
use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signature};
|
||||||
use crate::types::tuple::TupleSpec;
|
use crate::types::tuple::TupleSpec;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
CallableType, IntersectionType, KnownClass, MaterializationKind, MethodWrapperKind, Protocol,
|
BoundTypeVarInstance, CallableType, IntersectionType, KnownClass, MaterializationKind,
|
||||||
StringLiteralType, SubclassOfInner, Type, UnionType, WrapperDescriptorKind,
|
MethodWrapperKind, Protocol, ProtocolInstanceType, StringLiteralType, SubclassOfInner, Type,
|
||||||
|
UnionType, WrapperDescriptorKind,
|
||||||
};
|
};
|
||||||
use ruff_db::parsed::parsed_module;
|
use ruff_db::parsed::parsed_module;
|
||||||
|
|
||||||
|
|
@ -54,6 +55,58 @@ impl DisplaySettings {
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_possibly_ambiguous_type_pair<'db>(
|
||||||
|
db: &'db dyn Db,
|
||||||
|
type_1: Type<'db>,
|
||||||
|
type_2: Type<'db>,
|
||||||
|
) -> Self {
|
||||||
|
let result = Self::default();
|
||||||
|
|
||||||
|
let Some(class_1) = type_to_class_literal(db, type_1) else {
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(class_2) = type_to_class_literal(db, type_2) else {
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
if class_1 == class_2 {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if class_1.name(db) == class_2.name(db) {
|
||||||
|
result.qualified()
|
||||||
|
} else {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: generalize this to a method that takes any two types, walks them recursively, and returns
|
||||||
|
// a set of types with ambiguous names whose display should be qualified. Then we can use this in
|
||||||
|
// any diagnostic that displays two types.
|
||||||
|
fn type_to_class_literal<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option<ClassLiteral<'db>> {
|
||||||
|
match ty {
|
||||||
|
Type::ClassLiteral(class) => Some(class),
|
||||||
|
Type::NominalInstance(instance) => {
|
||||||
|
type_to_class_literal(db, Type::from(instance.class(db)))
|
||||||
|
}
|
||||||
|
Type::EnumLiteral(enum_literal) => Some(enum_literal.enum_class(db)),
|
||||||
|
Type::GenericAlias(alias) => Some(alias.origin(db)),
|
||||||
|
Type::ProtocolInstance(ProtocolInstanceType {
|
||||||
|
inner: Protocol::FromClass(class),
|
||||||
|
..
|
||||||
|
}) => type_to_class_literal(db, Type::from(class)),
|
||||||
|
Type::TypedDict(typed_dict) => {
|
||||||
|
type_to_class_literal(db, Type::from(typed_dict.defining_class()))
|
||||||
|
}
|
||||||
|
Type::SubclassOf(subclass_of) => {
|
||||||
|
type_to_class_literal(db, Type::from(subclass_of.subclass_of().into_class()?))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> Type<'db> {
|
impl<'db> Type<'db> {
|
||||||
|
|
@ -113,18 +166,25 @@ impl fmt::Debug for DisplayType<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the string representation of a type, which is the value displayed either as
|
impl<'db> ClassLiteral<'db> {
|
||||||
/// `Literal[<repr>]` or `Literal[<repr1>, <repr2>]` for literal types or as `<repr>` for
|
fn display_with(self, db: &'db dyn Db, settings: DisplaySettings) -> ClassDisplay<'db> {
|
||||||
/// non literals
|
ClassDisplay {
|
||||||
struct DisplayRepresentation<'db> {
|
db,
|
||||||
ty: Type<'db>,
|
class: self,
|
||||||
|
settings,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ClassDisplay<'db> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
|
class: ClassLiteral<'db>,
|
||||||
settings: DisplaySettings,
|
settings: DisplaySettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayRepresentation<'_> {
|
impl ClassDisplay<'_> {
|
||||||
fn class_parents(&self, class: ClassLiteral) -> Vec<String> {
|
fn class_parents(&self) -> Vec<String> {
|
||||||
let body_scope = class.body_scope(self.db);
|
let body_scope = self.class.body_scope(self.db);
|
||||||
let file = body_scope.file(self.db);
|
let file = body_scope.file(self.db);
|
||||||
let module_ast = parsed_module(self.db, file).load(self.db);
|
let module_ast = parsed_module(self.db, file).load(self.db);
|
||||||
let index = semantic_index(self.db, file);
|
let index = semantic_index(self.db, file);
|
||||||
|
|
@ -164,23 +224,29 @@ impl DisplayRepresentation<'_> {
|
||||||
name_parts.reverse();
|
name_parts.reverse();
|
||||||
name_parts
|
name_parts
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn write_maybe_qualified_class(
|
impl Display for ClassDisplay<'_> {
|
||||||
&self,
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
f: &mut Formatter<'_>,
|
|
||||||
class: ClassLiteral,
|
|
||||||
) -> fmt::Result {
|
|
||||||
if self.settings.qualified {
|
if self.settings.qualified {
|
||||||
let parents = self.class_parents(class);
|
for parent in self.class_parents() {
|
||||||
if !parents.is_empty() {
|
f.write_str(&parent)?;
|
||||||
f.write_str(&parents.join("."))?;
|
|
||||||
f.write_char('.')?;
|
f.write_char('.')?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.write_str(class.name(self.db))
|
f.write_str(self.class.name(self.db))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Writes the string representation of a type, which is the value displayed either as
|
||||||
|
/// `Literal[<repr>]` or `Literal[<repr1>, <repr2>]` for literal types or as `<repr>` for
|
||||||
|
/// non literals
|
||||||
|
struct DisplayRepresentation<'db> {
|
||||||
|
ty: Type<'db>,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
settings: DisplaySettings,
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for DisplayRepresentation<'_> {
|
impl Display for DisplayRepresentation<'_> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self.ty {
|
match self.ty {
|
||||||
|
|
@ -199,14 +265,14 @@ impl Display for DisplayRepresentation<'_> {
|
||||||
.display_with(self.db, self.settings)
|
.display_with(self.db, self.settings)
|
||||||
.fmt(f),
|
.fmt(f),
|
||||||
(ClassType::NonGeneric(class), _) => {
|
(ClassType::NonGeneric(class), _) => {
|
||||||
self.write_maybe_qualified_class(f, class)
|
class.display_with(self.db, self.settings).fmt(f)
|
||||||
},
|
},
|
||||||
(ClassType::Generic(alias), _) => alias.display_with(self.db, self.settings).fmt(f),
|
(ClassType::Generic(alias), _) => alias.display_with(self.db, self.settings).fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::ProtocolInstance(protocol) => match protocol.inner {
|
Type::ProtocolInstance(protocol) => match protocol.inner {
|
||||||
Protocol::FromClass(ClassType::NonGeneric(class)) => {
|
Protocol::FromClass(ClassType::NonGeneric(class)) => {
|
||||||
self.write_maybe_qualified_class(f, class)
|
class.display_with(self.db, self.settings).fmt(f)
|
||||||
}
|
}
|
||||||
Protocol::FromClass(ClassType::Generic(alias)) => {
|
Protocol::FromClass(ClassType::Generic(alias)) => {
|
||||||
alias.display_with(self.db, self.settings).fmt(f)
|
alias.display_with(self.db, self.settings).fmt(f)
|
||||||
|
|
@ -230,11 +296,11 @@ impl Display for DisplayRepresentation<'_> {
|
||||||
Type::ModuleLiteral(module) => {
|
Type::ModuleLiteral(module) => {
|
||||||
write!(f, "<module '{}'>", module.module(self.db).name(self.db))
|
write!(f, "<module '{}'>", module.module(self.db).name(self.db))
|
||||||
}
|
}
|
||||||
Type::ClassLiteral(class) => {
|
Type::ClassLiteral(class) => write!(
|
||||||
write!(f, "<class '")?;
|
f,
|
||||||
self.write_maybe_qualified_class(f, class)?;
|
"<class '{}'>",
|
||||||
write!(f, "'>")
|
class.display_with(self.db, self.settings)
|
||||||
}
|
),
|
||||||
Type::GenericAlias(generic) => write!(
|
Type::GenericAlias(generic) => write!(
|
||||||
f,
|
f,
|
||||||
"<class '{}'>",
|
"<class '{}'>",
|
||||||
|
|
@ -242,9 +308,7 @@ impl Display for DisplayRepresentation<'_> {
|
||||||
),
|
),
|
||||||
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
|
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
|
||||||
SubclassOfInner::Class(ClassType::NonGeneric(class)) => {
|
SubclassOfInner::Class(ClassType::NonGeneric(class)) => {
|
||||||
write!(f, "type[")?;
|
write!(f, "type[{}]", class.display_with(self.db, self.settings))
|
||||||
self.write_maybe_qualified_class(f, class)?;
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
}
|
||||||
SubclassOfInner::Class(ClassType::Generic(alias)) => {
|
SubclassOfInner::Class(ClassType::Generic(alias)) => {
|
||||||
write!(
|
write!(
|
||||||
|
|
@ -319,13 +383,13 @@ impl Display for DisplayRepresentation<'_> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet(_)) => {
|
Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet(_)) => {
|
||||||
write!(f, "<method-wrapper `__get__` of `property` object>",)
|
f.write_str("<method-wrapper `__get__` of `property` object>")
|
||||||
}
|
}
|
||||||
Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet(_)) => {
|
Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet(_)) => {
|
||||||
write!(f, "<method-wrapper `__set__` of `property` object>",)
|
f.write_str("<method-wrapper `__set__` of `property` object>")
|
||||||
}
|
}
|
||||||
Type::MethodWrapper(MethodWrapperKind::StrStartswith(_)) => {
|
Type::MethodWrapper(MethodWrapperKind::StrStartswith(_)) => {
|
||||||
write!(f, "<method-wrapper `startswith` of `str` object>",)
|
f.write_str("<method-wrapper `startswith` of `str` object>")
|
||||||
}
|
}
|
||||||
Type::WrapperDescriptor(kind) => {
|
Type::WrapperDescriptor(kind) => {
|
||||||
let (method, object) = match kind {
|
let (method, object) = match kind {
|
||||||
|
|
@ -354,18 +418,16 @@ impl Display for DisplayRepresentation<'_> {
|
||||||
|
|
||||||
escape.bytes_repr(TripleQuotes::No).write(f)
|
escape.bytes_repr(TripleQuotes::No).write(f)
|
||||||
}
|
}
|
||||||
Type::EnumLiteral(enum_literal) => {
|
Type::EnumLiteral(enum_literal) => write!(
|
||||||
self.write_maybe_qualified_class(f, enum_literal.enum_class(self.db))?;
|
f,
|
||||||
f.write_char('.')?;
|
"{enum_class}.{literal_name}",
|
||||||
f.write_str(enum_literal.name(self.db))
|
enum_class = enum_literal
|
||||||
}
|
.enum_class(self.db)
|
||||||
|
.display_with(self.db, self.settings),
|
||||||
|
literal_name = enum_literal.name(self.db)
|
||||||
|
),
|
||||||
Type::NonInferableTypeVar(bound_typevar) | Type::TypeVar(bound_typevar) => {
|
Type::NonInferableTypeVar(bound_typevar) | Type::TypeVar(bound_typevar) => {
|
||||||
f.write_str(bound_typevar.typevar(self.db).name(self.db))?;
|
bound_typevar.display(self.db).fmt(f)
|
||||||
if let Some(binding_context) = bound_typevar.binding_context(self.db).name(self.db)
|
|
||||||
{
|
|
||||||
write!(f, "@{binding_context}")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
Type::AlwaysTruthy => f.write_str("AlwaysTruthy"),
|
Type::AlwaysTruthy => f.write_str("AlwaysTruthy"),
|
||||||
Type::AlwaysFalsy => f.write_str("AlwaysFalsy"),
|
Type::AlwaysFalsy => f.write_str("AlwaysFalsy"),
|
||||||
|
|
@ -393,15 +455,41 @@ impl Display for DisplayRepresentation<'_> {
|
||||||
}
|
}
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
}
|
}
|
||||||
Type::TypedDict(typed_dict) => self.write_maybe_qualified_class(
|
Type::TypedDict(typed_dict) => typed_dict
|
||||||
f,
|
.defining_class()
|
||||||
typed_dict.defining_class().class_literal(self.db).0,
|
.class_literal(self.db)
|
||||||
),
|
.0
|
||||||
|
.display_with(self.db, self.settings)
|
||||||
|
.fmt(f),
|
||||||
Type::TypeAlias(alias) => f.write_str(alias.name(self.db)),
|
Type::TypeAlias(alias) => f.write_str(alias.name(self.db)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'db> BoundTypeVarInstance<'db> {
|
||||||
|
pub(crate) fn display(self, db: &'db dyn Db) -> impl Display {
|
||||||
|
DisplayBoundTypeVarInstance {
|
||||||
|
bound_typevar: self,
|
||||||
|
db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DisplayBoundTypeVarInstance<'db> {
|
||||||
|
bound_typevar: BoundTypeVarInstance<'db>,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for DisplayBoundTypeVarInstance<'_> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str(self.bound_typevar.typevar(self.db).name(self.db))?;
|
||||||
|
if let Some(binding_context) = self.bound_typevar.binding_context(self.db).name(self.db) {
|
||||||
|
write!(f, "@{binding_context}")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'db> TupleSpec<'db> {
|
impl<'db> TupleSpec<'db> {
|
||||||
pub(crate) fn display_with(
|
pub(crate) fn display_with(
|
||||||
&'db self,
|
&'db self,
|
||||||
|
|
@ -627,7 +715,7 @@ impl Display for DisplayGenericAlias<'_> {
|
||||||
f,
|
f,
|
||||||
"{prefix}{origin}{specialization}{suffix}",
|
"{prefix}{origin}{specialization}{suffix}",
|
||||||
prefix = prefix,
|
prefix = prefix,
|
||||||
origin = self.origin.name(self.db),
|
origin = self.origin.display_with(self.db, self.settings),
|
||||||
specialization = self.specialization.display_short(
|
specialization = self.specialization.display_short(
|
||||||
self.db,
|
self.db,
|
||||||
TupleSpecialization::from_class(self.db, self.origin)
|
TupleSpecialization::from_class(self.db, self.origin)
|
||||||
|
|
|
||||||
|
|
@ -801,7 +801,7 @@ pub struct CallSignatureDetails<'db> {
|
||||||
|
|
||||||
/// Mapping from argument indices to parameter indices. This helps
|
/// Mapping from argument indices to parameter indices. This helps
|
||||||
/// determine which parameter corresponds to which argument position.
|
/// determine which parameter corresponds to which argument position.
|
||||||
pub argument_to_parameter_mapping: Vec<MatchedArgument>,
|
pub argument_to_parameter_mapping: Vec<MatchedArgument<'db>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract signature details from a function call expression.
|
/// Extract signature details from a function call expression.
|
||||||
|
|
@ -821,7 +821,9 @@ pub fn call_signature_details<'db>(
|
||||||
CallArguments::from_arguments(db, &call_expr.arguments, |_, splatted_value| {
|
CallArguments::from_arguments(db, &call_expr.arguments, |_, splatted_value| {
|
||||||
splatted_value.inferred_type(model)
|
splatted_value.inferred_type(model)
|
||||||
});
|
});
|
||||||
let bindings = callable_type.bindings(db).match_parameters(&call_arguments);
|
let bindings = callable_type
|
||||||
|
.bindings(db)
|
||||||
|
.match_parameters(db, &call_arguments);
|
||||||
|
|
||||||
// Extract signature details from all callable bindings
|
// Extract signature details from all callable bindings
|
||||||
bindings
|
bindings
|
||||||
|
|
|
||||||
|
|
@ -102,12 +102,12 @@ use crate::types::diagnostic::{
|
||||||
INVALID_TYPE_VARIABLE_CONSTRAINTS, IncompatibleBases, POSSIBLY_UNBOUND_IMPLICIT_CALL,
|
INVALID_TYPE_VARIABLE_CONSTRAINTS, IncompatibleBases, POSSIBLY_UNBOUND_IMPLICIT_CALL,
|
||||||
POSSIBLY_UNBOUND_IMPORT, TypeCheckDiagnostics, UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE,
|
POSSIBLY_UNBOUND_IMPORT, TypeCheckDiagnostics, UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE,
|
||||||
UNRESOLVED_GLOBAL, UNRESOLVED_IMPORT, UNRESOLVED_REFERENCE, UNSUPPORTED_OPERATOR,
|
UNRESOLVED_GLOBAL, UNRESOLVED_IMPORT, UNRESOLVED_REFERENCE, UNSUPPORTED_OPERATOR,
|
||||||
report_implicit_return_type, report_instance_layout_conflict,
|
report_attempted_write_to_read_only_property, report_implicit_return_type,
|
||||||
report_invalid_argument_number_to_special_form, report_invalid_arguments_to_annotated,
|
report_instance_layout_conflict, report_invalid_argument_number_to_special_form,
|
||||||
report_invalid_arguments_to_callable, report_invalid_assignment,
|
report_invalid_arguments_to_annotated, report_invalid_arguments_to_callable,
|
||||||
report_invalid_attribute_assignment, report_invalid_generator_function_return_type,
|
report_invalid_assignment, report_invalid_attribute_assignment,
|
||||||
report_invalid_key_on_typed_dict, report_invalid_return_type,
|
report_invalid_generator_function_return_type, report_invalid_key_on_typed_dict,
|
||||||
report_namedtuple_field_without_default_after_field_with_default,
|
report_invalid_return_type, report_namedtuple_field_without_default_after_field_with_default,
|
||||||
report_possibly_unbound_attribute,
|
report_possibly_unbound_attribute,
|
||||||
};
|
};
|
||||||
use crate::types::enums::is_enum_class;
|
use crate::types::enums::is_enum_class;
|
||||||
|
|
@ -4033,13 +4033,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AttributeAssignmentError::ReadOnlyProperty => {
|
AttributeAssignmentError::ReadOnlyProperty(property) => {
|
||||||
if let Some(builder) = self.context.report_lint(&INVALID_ASSIGNMENT, target) {
|
report_attempted_write_to_read_only_property(
|
||||||
builder.into_diagnostic(format_args!(
|
&self.context,
|
||||||
"Property `{attribute}` defined in `{ty}` is read-only",
|
property,
|
||||||
ty = object_ty.display(self.db()),
|
attribute,
|
||||||
));
|
object_ty,
|
||||||
}
|
target,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
AttributeAssignmentError::FailToSet => {
|
AttributeAssignmentError::FailToSet => {
|
||||||
if let Some(builder) = self.context.report_lint(&INVALID_ASSIGNMENT, target) {
|
if let Some(builder) = self.context.report_lint(&INVALID_ASSIGNMENT, target) {
|
||||||
|
|
@ -5944,7 +5945,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
|
|
||||||
let bindings = callable_type
|
let bindings = callable_type
|
||||||
.bindings(self.db())
|
.bindings(self.db())
|
||||||
.match_parameters(&call_arguments);
|
.match_parameters(self.db(), &call_arguments);
|
||||||
self.infer_argument_types(arguments, &mut call_arguments, &bindings.argument_forms);
|
self.infer_argument_types(arguments, &mut call_arguments, &bindings.argument_forms);
|
||||||
|
|
||||||
// Validate `TypedDict` constructor calls after argument type inference
|
// Validate `TypedDict` constructor calls after argument type inference
|
||||||
|
|
@ -8396,7 +8397,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
};
|
};
|
||||||
let binding = Binding::single(value_ty, generic_context.signature(self.db()));
|
let binding = Binding::single(value_ty, generic_context.signature(self.db()));
|
||||||
let bindings = match Bindings::from(binding)
|
let bindings = match Bindings::from(binding)
|
||||||
.match_parameters(&call_argument_types)
|
.match_parameters(self.db(), &call_argument_types)
|
||||||
.check_types(self.db(), &call_argument_types)
|
.check_types(self.db(), &call_argument_types)
|
||||||
{
|
{
|
||||||
Ok(bindings) => bindings,
|
Ok(bindings) => bindings,
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use super::protocol_class::ProtocolInterface;
|
||||||
use super::{BoundTypeVarInstance, ClassType, KnownClass, SubclassOfType, Type, TypeVarVariance};
|
use super::{BoundTypeVarInstance, ClassType, KnownClass, SubclassOfType, Type, TypeVarVariance};
|
||||||
use crate::place::PlaceAndQualifiers;
|
use crate::place::PlaceAndQualifiers;
|
||||||
use crate::semantic_index::definition::Definition;
|
use crate::semantic_index::definition::Definition;
|
||||||
use crate::types::constraints::{Constraints, IteratorConstraintsExtension};
|
use crate::types::constraints::{ConstraintSet, Constraints, IteratorConstraintsExtension};
|
||||||
use crate::types::enums::is_single_member_enum;
|
use crate::types::enums::is_single_member_enum;
|
||||||
use crate::types::protocol_class::walk_protocol_interface;
|
use crate::types::protocol_class::walk_protocol_interface;
|
||||||
use crate::types::tuple::{TupleSpec, TupleType};
|
use crate::types::tuple::{TupleSpec, TupleType};
|
||||||
|
|
@ -513,12 +513,15 @@ impl<'db> ProtocolInstanceType<'db> {
|
||||||
visitor: &NormalizedVisitor<'db>,
|
visitor: &NormalizedVisitor<'db>,
|
||||||
) -> Type<'db> {
|
) -> Type<'db> {
|
||||||
let object = Type::object(db);
|
let object = Type::object(db);
|
||||||
if object.satisfies_protocol(
|
if object
|
||||||
db,
|
.satisfies_protocol(
|
||||||
self,
|
db,
|
||||||
TypeRelation::Subtyping,
|
self,
|
||||||
&HasRelationToVisitor::new(true),
|
TypeRelation::Subtyping,
|
||||||
) {
|
&HasRelationToVisitor::new(ConstraintSet::always_satisfiable(db)),
|
||||||
|
)
|
||||||
|
.is_always_satisfied(db)
|
||||||
|
{
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
match self.inner {
|
match self.inner {
|
||||||
|
|
|
||||||
|
|
@ -638,7 +638,7 @@ impl<'a, 'db> ProtocolMember<'a, 'db> {
|
||||||
pub(super) fn instance_set_type(&self) -> Result<Type<'db>, AttributeAssignmentError<'db>> {
|
pub(super) fn instance_set_type(&self) -> Result<Type<'db>, AttributeAssignmentError<'db>> {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
ProtocolMemberKind::Property { set_type, .. } => {
|
ProtocolMemberKind::Property { set_type, .. } => {
|
||||||
set_type.ok_or(AttributeAssignmentError::ReadOnlyProperty)
|
set_type.ok_or(AttributeAssignmentError::ReadOnlyProperty(None))
|
||||||
}
|
}
|
||||||
ProtocolMemberKind::Method(_) => Err(AttributeAssignmentError::CannotAssign),
|
ProtocolMemberKind::Method(_) => Err(AttributeAssignmentError::CannotAssign),
|
||||||
ProtocolMemberKind::Attribute(ty) => {
|
ProtocolMemberKind::Attribute(ty) => {
|
||||||
|
|
@ -689,7 +689,8 @@ impl<'a, 'db> ProtocolMember<'a, 'db> {
|
||||||
db,
|
db,
|
||||||
matches!(
|
matches!(
|
||||||
other.to_meta_type(db).member(db, self.name).place,
|
other.to_meta_type(db).member(db, self.name).place,
|
||||||
Place::Type(_, Boundness::Bound)
|
Place::Type(ty, Boundness::Bound)
|
||||||
|
if ty.is_assignable_to(db, CallableType::single(db, Signature::dynamic(Type::any())))
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use smallvec::{SmallVec, smallvec_inline};
|
||||||
|
|
||||||
use super::{DynamicType, Type, TypeVarVariance, definition_expression_type};
|
use super::{DynamicType, Type, TypeVarVariance, definition_expression_type};
|
||||||
use crate::semantic_index::definition::Definition;
|
use crate::semantic_index::definition::Definition;
|
||||||
use crate::types::constraints::{Constraints, IteratorConstraintsExtension};
|
use crate::types::constraints::{ConstraintSet, Constraints, IteratorConstraintsExtension};
|
||||||
use crate::types::generics::{GenericContext, walk_generic_context};
|
use crate::types::generics::{GenericContext, walk_generic_context};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
BindingContext, BoundTypeVarInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor,
|
BindingContext, BoundTypeVarInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor,
|
||||||
|
|
@ -123,7 +123,8 @@ impl<'db> CallableSignature<'db> {
|
||||||
///
|
///
|
||||||
/// See [`Type::is_subtype_of`] for more details.
|
/// See [`Type::is_subtype_of`] for more details.
|
||||||
pub(crate) fn is_subtype_of(&self, db: &'db dyn Db, other: &Self) -> bool {
|
pub(crate) fn is_subtype_of(&self, db: &'db dyn Db, other: &Self) -> bool {
|
||||||
self.is_subtype_of_impl(db, other)
|
self.is_subtype_of_impl::<ConstraintSet>(db, other)
|
||||||
|
.is_always_satisfied(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_subtype_of_impl<C: Constraints<'db>>(&self, db: &'db dyn Db, other: &Self) -> C {
|
fn is_subtype_of_impl<C: Constraints<'db>>(&self, db: &'db dyn Db, other: &Self) -> C {
|
||||||
|
|
@ -143,8 +144,9 @@ impl<'db> CallableSignature<'db> {
|
||||||
db,
|
db,
|
||||||
other,
|
other,
|
||||||
TypeRelation::Assignability,
|
TypeRelation::Assignability,
|
||||||
&HasRelationToVisitor::new(true),
|
&HasRelationToVisitor::new(ConstraintSet::always_satisfiable(db)),
|
||||||
)
|
)
|
||||||
|
.is_always_satisfied(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn has_relation_to_impl<C: Constraints<'db>>(
|
pub(crate) fn has_relation_to_impl<C: Constraints<'db>>(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue