mirror of https://github.com/astral-sh/ruff
[ty] Reduce indentation of `TypeInferenceBuilder::infer_attribute_load` (#21560)
This commit is contained in:
parent
59c6cb521d
commit
762c44527e
|
|
@ -32,7 +32,7 @@ use ruff_db::diagnostic::{Annotation, Diagnostic, Span, SubDiagnostic, SubDiagno
|
||||||
use ruff_db::source::source_text;
|
use ruff_db::source::source_text;
|
||||||
use ruff_python_ast::name::Name;
|
use ruff_python_ast::name::Name;
|
||||||
use ruff_python_ast::parenthesize::parentheses_iterator;
|
use ruff_python_ast::parenthesize::parentheses_iterator;
|
||||||
use ruff_python_ast::{self as ast, AnyNodeRef, Identifier};
|
use ruff_python_ast::{self as ast, AnyNodeRef};
|
||||||
use ruff_python_trivia::CommentRanges;
|
use ruff_python_trivia::CommentRanges;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
@ -3427,7 +3427,7 @@ pub(super) fn hint_if_stdlib_attribute_exists_on_other_versions(
|
||||||
db: &dyn Db,
|
db: &dyn Db,
|
||||||
mut diagnostic: LintDiagnosticGuard,
|
mut diagnostic: LintDiagnosticGuard,
|
||||||
value_type: &Type,
|
value_type: &Type,
|
||||||
attr: &Identifier,
|
attr: &str,
|
||||||
) {
|
) {
|
||||||
// Currently we limit this analysis to attributes of stdlib modules,
|
// Currently we limit this analysis to attributes of stdlib modules,
|
||||||
// as this covers the most important cases while not being too noisy
|
// as this covers the most important cases while not being too noisy
|
||||||
|
|
@ -3461,6 +3461,6 @@ pub(super) fn hint_if_stdlib_attribute_exists_on_other_versions(
|
||||||
add_inferred_python_version_hint_to_diagnostic(
|
add_inferred_python_version_hint_to_diagnostic(
|
||||||
db,
|
db,
|
||||||
&mut diagnostic,
|
&mut diagnostic,
|
||||||
&format!("accessing `{}`", attr.id),
|
&format!("accessing `{attr}`"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9012,7 +9012,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
assigned_type = Some(ty);
|
assigned_type = Some(ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let fallback_place = value_type.member(db, &attr.id);
|
let mut fallback_place = value_type.member(db, &attr.id);
|
||||||
// Exclude non-definitely-bound places for purposes of reachability
|
// Exclude non-definitely-bound places for purposes of reachability
|
||||||
// analysis. We currently do not perform boundness analysis for implicit
|
// analysis. We currently do not perform boundness analysis for implicit
|
||||||
// instance attributes, so we exclude them here as well.
|
// instance attributes, so we exclude them here as well.
|
||||||
|
|
@ -9024,14 +9024,26 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
self.all_definitely_bound = false;
|
self.all_definitely_bound = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let resolved_type =
|
fallback_place = fallback_place.map_type(|ty| {
|
||||||
fallback_place.map_type(|ty| {
|
|
||||||
self.narrow_expr_with_applicable_constraints(attribute, ty, &constraint_keys)
|
self.narrow_expr_with_applicable_constraints(attribute, ty, &constraint_keys)
|
||||||
}).unwrap_with_diagnostic(|lookup_error| match lookup_error {
|
});
|
||||||
LookupError::Undefined(_) => {
|
|
||||||
let report_unresolved_attribute = self.is_reachable(attribute);
|
let attr_name = &attr.id;
|
||||||
|
|
||||||
|
let resolved_type = fallback_place.unwrap_with_diagnostic(|lookup_err| match lookup_err {
|
||||||
|
LookupError::Undefined(_) => {
|
||||||
|
let fallback = || {
|
||||||
|
TypeAndQualifiers::new(
|
||||||
|
Type::unknown(),
|
||||||
|
TypeOrigin::Inferred,
|
||||||
|
TypeQualifiers::empty(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if !self.is_reachable(attribute) {
|
||||||
|
return fallback();
|
||||||
|
}
|
||||||
|
|
||||||
if report_unresolved_attribute {
|
|
||||||
let bound_on_instance = match value_type {
|
let bound_on_instance = match value_type {
|
||||||
Type::ClassLiteral(class) => {
|
Type::ClassLiteral(class) => {
|
||||||
!class.instance_member(db, None, attr).is_undefined()
|
!class.instance_member(db, None, attr).is_undefined()
|
||||||
|
|
@ -9042,73 +9054,68 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
!class.instance_member(db, attr).is_undefined()
|
!class.instance_member(db, attr).is_undefined()
|
||||||
}
|
}
|
||||||
SubclassOfInner::Dynamic(_) => unreachable!(
|
SubclassOfInner::Dynamic(_) => unreachable!(
|
||||||
"Attribute lookup on a dynamic `SubclassOf` type should always return a bound symbol"
|
"Attribute lookup on a dynamic `SubclassOf` type \
|
||||||
|
should always return a bound symbol"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(builder) = self
|
let Some(builder) = self.context.report_lint(&UNRESOLVED_ATTRIBUTE, attribute)
|
||||||
.context
|
else {
|
||||||
.report_lint(&UNRESOLVED_ATTRIBUTE, attribute)
|
return fallback();
|
||||||
{
|
|
||||||
if bound_on_instance {
|
|
||||||
builder.into_diagnostic(
|
|
||||||
format_args!(
|
|
||||||
"Attribute `{}` can only be accessed on instances, \
|
|
||||||
not on the class object `{}` itself.",
|
|
||||||
attr.id,
|
|
||||||
value_type.display(db)
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let diagnostic = match value_type {
|
|
||||||
Type::ModuleLiteral(module) => builder.into_diagnostic(format_args!(
|
|
||||||
"Module `{}` has no member `{}`",
|
|
||||||
module.module(db).name(db),
|
|
||||||
&attr.id
|
|
||||||
)),
|
|
||||||
Type::ClassLiteral(class) => builder.into_diagnostic(format_args!(
|
|
||||||
"Class `{}` has no attribute `{}`",
|
|
||||||
class.name(db),
|
|
||||||
&attr.id
|
|
||||||
)),
|
|
||||||
Type::GenericAlias(alias) => builder.into_diagnostic(format_args!(
|
|
||||||
"Class `{}` has no attribute `{}`",
|
|
||||||
alias.display(db),
|
|
||||||
&attr.id
|
|
||||||
)),
|
|
||||||
Type::FunctionLiteral(function) => builder.into_diagnostic(format_args!(
|
|
||||||
"Function `{}` has no attribute `{}`",
|
|
||||||
function.name(db),
|
|
||||||
&attr.id
|
|
||||||
)),
|
|
||||||
_ => builder.into_diagnostic(format_args!(
|
|
||||||
"Object of type `{}` has no attribute `{}`",
|
|
||||||
value_type.display(db),
|
|
||||||
&attr.id
|
|
||||||
)),
|
|
||||||
};
|
};
|
||||||
hint_if_stdlib_attribute_exists_on_other_versions(db, diagnostic, &value_type, attr);
|
|
||||||
}
|
if bound_on_instance {
|
||||||
}
|
builder.into_diagnostic(format_args!(
|
||||||
|
"Attribute `{attr_name}` can only be accessed on instances, \
|
||||||
|
not on the class object `{}` itself.",
|
||||||
|
value_type.display(db)
|
||||||
|
));
|
||||||
|
return fallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeAndQualifiers::new(Type::unknown(), TypeOrigin::Inferred, TypeQualifiers::empty())
|
let diagnostic = match value_type {
|
||||||
|
Type::ModuleLiteral(module) => builder.into_diagnostic(format_args!(
|
||||||
|
"Module `{}` has no member `{attr_name}`",
|
||||||
|
module.module(db).name(db),
|
||||||
|
)),
|
||||||
|
Type::ClassLiteral(class) => builder.into_diagnostic(format_args!(
|
||||||
|
"Class `{}` has no attribute `{attr_name}`",
|
||||||
|
class.name(db),
|
||||||
|
)),
|
||||||
|
Type::GenericAlias(alias) => builder.into_diagnostic(format_args!(
|
||||||
|
"Class `{}` has no attribute `{attr_name}`",
|
||||||
|
alias.display(db),
|
||||||
|
)),
|
||||||
|
Type::FunctionLiteral(function) => builder.into_diagnostic(format_args!(
|
||||||
|
"Function `{}` has no attribute `{attr_name}`",
|
||||||
|
function.name(db),
|
||||||
|
)),
|
||||||
|
_ => builder.into_diagnostic(format_args!(
|
||||||
|
"Object of type `{}` has no attribute `{attr_name}`",
|
||||||
|
value_type.display(db),
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
|
||||||
|
hint_if_stdlib_attribute_exists_on_other_versions(
|
||||||
|
db,
|
||||||
|
diagnostic,
|
||||||
|
&value_type,
|
||||||
|
attr_name,
|
||||||
|
);
|
||||||
|
|
||||||
|
fallback()
|
||||||
}
|
}
|
||||||
LookupError::PossiblyUndefined(type_when_bound) => {
|
LookupError::PossiblyUndefined(type_when_bound) => {
|
||||||
report_possibly_missing_attribute(
|
report_possibly_missing_attribute(&self.context, attribute, &attr.id, value_type);
|
||||||
&self.context,
|
|
||||||
attribute,
|
|
||||||
&attr.id,
|
|
||||||
value_type,
|
|
||||||
);
|
|
||||||
|
|
||||||
type_when_bound
|
type_when_bound
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.inner_type();
|
|
||||||
|
let resolved_type = resolved_type.inner_type();
|
||||||
|
|
||||||
self.check_deprecated(attr, resolved_type);
|
self.check_deprecated(attr, resolved_type);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue