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_python_ast::name::Name;
|
||||
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_text_size::{Ranged, TextRange};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
|
@ -3427,7 +3427,7 @@ pub(super) fn hint_if_stdlib_attribute_exists_on_other_versions(
|
|||
db: &dyn Db,
|
||||
mut diagnostic: LintDiagnosticGuard,
|
||||
value_type: &Type,
|
||||
attr: &Identifier,
|
||||
attr: &str,
|
||||
) {
|
||||
// Currently we limit this analysis to attributes of stdlib modules,
|
||||
// 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(
|
||||
db,
|
||||
&mut diagnostic,
|
||||
&format!("accessing `{}`", attr.id),
|
||||
&format!("accessing `{attr}`"),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9012,7 +9012,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
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
|
||||
// analysis. We currently do not perform boundness analysis for implicit
|
||||
// instance attributes, so we exclude them here as well.
|
||||
|
|
@ -9024,14 +9024,26 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
self.all_definitely_bound = false;
|
||||
}
|
||||
|
||||
let resolved_type =
|
||||
fallback_place.map_type(|ty| {
|
||||
fallback_place = fallback_place.map_type(|ty| {
|
||||
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 {
|
||||
Type::ClassLiteral(class) => {
|
||||
!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()
|
||||
}
|
||||
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,
|
||||
};
|
||||
|
||||
if let Some(builder) = self
|
||||
.context
|
||||
.report_lint(&UNRESOLVED_ATTRIBUTE, attribute)
|
||||
{
|
||||
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
|
||||
)),
|
||||
let Some(builder) = self.context.report_lint(&UNRESOLVED_ATTRIBUTE, attribute)
|
||||
else {
|
||||
return fallback();
|
||||
};
|
||||
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) => {
|
||||
report_possibly_missing_attribute(
|
||||
&self.context,
|
||||
attribute,
|
||||
&attr.id,
|
||||
value_type,
|
||||
);
|
||||
report_possibly_missing_attribute(&self.context, attribute, &attr.id, value_type);
|
||||
|
||||
type_when_bound
|
||||
}
|
||||
})
|
||||
.inner_type();
|
||||
});
|
||||
|
||||
let resolved_type = resolved_type.inner_type();
|
||||
|
||||
self.check_deprecated(attr, resolved_type);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue