Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/ty_python_semantic/src/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ impl<'db> Place<'db> {
Place::Unbound => Place::Unbound,
}
}

pub(crate) fn is_definitely_bound(&self) -> bool {
matches!(self, Place::Type(_, Boundness::Bound))
}
}

impl<'db> From<LookupResult<'db>> for PlaceAndQualifiers<'db> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ use crate::semantic_index::predicate::{
Predicates, ScopedPredicateId,
};
use crate::types::{
IntersectionBuilder, Truthiness, Type, UnionBuilder, UnionType, infer_expression_type,
IntersectionBuilder, Truthiness, Type, UnionBuilder, UnionType,
infer_expression_if_definitely_bound, infer_expression_type,
};

/// A ternary formula that defines under what conditions a binding is visible. (A ternary formula
Expand Down Expand Up @@ -799,7 +800,7 @@ impl ReachabilityConstraints {
fn analyze_single(db: &dyn Db, predicate: &Predicate) -> Truthiness {
match predicate.node {
PredicateNode::Expression(test_expr) => {
let ty = infer_expression_type(db, test_expr);
let ty = infer_expression_if_definitely_bound(db, test_expr);
ty.bool(db).negate_if(!predicate.is_positive)
}
PredicateNode::ReturnsNever(CallableAndCallExpr {
Expand Down
6 changes: 4 additions & 2 deletions crates/ty_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ pub(crate) use self::cyclic::{PairVisitor, TypeTransformer};
pub use self::diagnostic::TypeCheckDiagnostics;
pub(crate) use self::diagnostic::register_lints;
pub(crate) use self::infer::{
infer_deferred_types, infer_definition_types, infer_expression_type, infer_expression_types,
infer_scope_types,
infer_deferred_types, infer_definition_types, infer_expression_if_definitely_bound,
infer_expression_type, infer_expression_types, infer_scope_types,
};
pub(crate) use self::signatures::{CallableSignature, Signature};
pub(crate) use self::subclass_of::{SubclassOfInner, SubclassOfType};
Expand Down Expand Up @@ -6581,6 +6581,8 @@ bitflags! {
const FINAL = 1 << 1;
/// `dataclasses.InitVar`
const INIT_VAR = 1 << 2;
/// HACK to determine if this place was not bound but we consider it bound
const NOT_BOUND = 1 << 3;
}
}

Expand Down
13 changes: 8 additions & 5 deletions crates/ty_python_semantic/src/types/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2516,17 +2516,20 @@ impl<'db> ClassLiteral<'db> {
// self.name: <annotation>
// self.name: <annotation> = …

if use_def_map(db, method_scope)
.is_declaration_reachable(db, &attribute_declaration)
.is_always_false()
{
let reachability = use_def_map(db, method_scope)
.is_declaration_reachable(db, &attribute_declaration);

if reachability.is_always_false() {
continue;
}

let annotation = declaration_type(db, declaration);
let annotation =
let mut annotation =
Place::bound(annotation.inner).with_qualifiers(annotation.qualifiers);

if reachability.is_ambiguous() {
annotation.qualifiers |= TypeQualifiers::NOT_BOUND;
}
if let Some(all_qualifiers) = annotation.is_bare_final() {
if let Some(value) = assignment.value(&module) {
// If we see an annotated assignment with a bare `Final` as in
Expand Down
Loading
Loading