Skip to content

Commit 5172ba6

Browse files
ibraheemdevthejchap
authored andcommitted
Support relative --ty-path in ty-benchmark (#18385)
## Summary This currently doesn't work because the benchmark changes the working directory. Also updates the process name to make it easier to compare two local ty binaries.
1 parent aa1fad6 commit 5172ba6

File tree

1 file changed

+149
-129
lines changed
  • crates/ty_python_semantic/src/types

1 file changed

+149
-129
lines changed

crates/ty_python_semantic/src/types/infer.rs

Lines changed: 149 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -3113,87 +3113,163 @@ impl<'db> TypeInferenceBuilder<'db> {
31133113
dataclass_params.is_some_and(|params| params.contains(DataclassParams::FROZEN))
31143114
};
31153115

3116-
match object_ty.class_member(db, attribute.into()) {
3117-
meta_attr @ SymbolAndQualifiers { .. } if meta_attr.is_class_var() => {
3116+
// First, try to call the `__setattr__` dunder method. If this is present/defined, overrides
3117+
// assigning the attributed by the normal mechanism.
3118+
let setattr_dunder_call_result = object_ty.try_call_dunder_with_policy(
3119+
db,
3120+
"__setattr__",
3121+
&mut CallArgumentTypes::positional([
3122+
Type::StringLiteral(StringLiteralType::new(db, Box::from(attribute))),
3123+
value_ty,
3124+
]),
3125+
MemberLookupPolicy::MRO_NO_OBJECT_FALLBACK,
3126+
);
3127+
3128+
match setattr_dunder_call_result {
3129+
Ok(result) => match result.return_type(db) {
3130+
Type::Never => {
3131+
if emit_diagnostics {
3132+
if let Some(builder) =
3133+
self.context.report_lint(&INVALID_ASSIGNMENT, target)
3134+
{
3135+
builder.into_diagnostic(format_args!(
3136+
"Cannot assign to attribute `{attribute}` on type `{}` \
3137+
via `__setattr__` that returns `Never`",
3138+
object_ty.display(db)
3139+
));
3140+
}
3141+
}
3142+
false
3143+
}
3144+
_ => true,
3145+
},
3146+
Err(CallDunderError::CallError(kind, _)) => {
3147+
println!("{kind:?} {object_ty:?} {attribute:?} {value_ty:?}");
31183148
if emit_diagnostics {
31193149
if let Some(builder) =
3120-
self.context.report_lint(&INVALID_ATTRIBUTE_ACCESS, target)
3150+
self.context.report_lint(&UNRESOLVED_ATTRIBUTE, target)
31213151
{
31223152
builder.into_diagnostic(format_args!(
3123-
"Cannot assign to ClassVar `{attribute}` \
3124-
from an instance of type `{ty}`",
3125-
ty = object_ty.display(self.db()),
3153+
"Can not assign object of `{}` to attribute \
3154+
`{attribute}` on type `{}` with \
3155+
custom `__setattr__` method.",
3156+
value_ty.display(db),
3157+
object_ty.display(db)
31263158
));
31273159
}
31283160
}
31293161
false
31303162
}
3131-
SymbolAndQualifiers {
3132-
symbol: Symbol::Type(meta_attr_ty, meta_attr_boundness),
3133-
qualifiers: _,
3134-
} => {
3135-
if is_read_only() {
3136-
if emit_diagnostics {
3137-
if let Some(builder) =
3138-
self.context.report_lint(&INVALID_ASSIGNMENT, target)
3139-
{
3140-
builder.into_diagnostic(format_args!(
3163+
Err(CallDunderError::PossiblyUnbound(_)) => true,
3164+
Err(CallDunderError::MethodNotAvailable) => {
3165+
match object_ty.class_member(db, attribute.into()) {
3166+
meta_attr @ SymbolAndQualifiers { .. } if meta_attr.is_class_var() => {
3167+
if emit_diagnostics {
3168+
if let Some(builder) =
3169+
self.context.report_lint(&INVALID_ATTRIBUTE_ACCESS, target)
3170+
{
3171+
builder.into_diagnostic(format_args!(
3172+
"Cannot assign to ClassVar `{attribute}` \
3173+
from an instance of type `{ty}`",
3174+
ty = object_ty.display(self.db()),
3175+
));
3176+
}
3177+
}
3178+
false
3179+
}
3180+
SymbolAndQualifiers {
3181+
symbol: Symbol::Type(meta_attr_ty, meta_attr_boundness),
3182+
qualifiers: _,
3183+
} => {
3184+
if is_read_only() {
3185+
if emit_diagnostics {
3186+
if let Some(builder) =
3187+
self.context.report_lint(&INVALID_ASSIGNMENT, target)
3188+
{
3189+
builder.into_diagnostic(format_args!(
31413190
"Property `{attribute}` defined in `{ty}` is read-only",
31423191
ty = object_ty.display(self.db()),
31433192
));
3144-
}
3145-
}
3146-
false
3147-
} else {
3148-
let assignable_to_meta_attr = if let Symbol::Type(meta_dunder_set, _) =
3149-
meta_attr_ty.class_member(db, "__set__".into()).symbol
3150-
{
3151-
let successful_call = meta_dunder_set
3152-
.try_call(
3153-
db,
3154-
&CallArgumentTypes::positional([
3155-
meta_attr_ty,
3156-
object_ty,
3157-
value_ty,
3158-
]),
3159-
)
3160-
.is_ok();
3193+
}
3194+
}
3195+
false
3196+
} else {
3197+
let assignable_to_meta_attr =
3198+
if let Symbol::Type(meta_dunder_set, _) =
3199+
meta_attr_ty.class_member(db, "__set__".into()).symbol
3200+
{
3201+
let successful_call = meta_dunder_set
3202+
.try_call(
3203+
db,
3204+
&CallArgumentTypes::positional([
3205+
meta_attr_ty,
3206+
object_ty,
3207+
value_ty,
3208+
]),
3209+
)
3210+
.is_ok();
31613211

3162-
if !successful_call && emit_diagnostics {
3163-
if let Some(builder) =
3164-
self.context.report_lint(&INVALID_ASSIGNMENT, target)
3165-
{
3166-
// TODO: Here, it would be nice to emit an additional diagnostic that explains why the call failed
3167-
builder.into_diagnostic(format_args!(
3212+
if !successful_call && emit_diagnostics {
3213+
if let Some(builder) = self
3214+
.context
3215+
.report_lint(&INVALID_ASSIGNMENT, target)
3216+
{
3217+
// TODO: Here, it would be nice to emit an additional diagnostic that explains why the call failed
3218+
builder.into_diagnostic(format_args!(
31683219
"Invalid assignment to data descriptor attribute \
31693220
`{attribute}` on type `{}` with custom `__set__` method",
31703221
object_ty.display(db)
31713222
));
3172-
}
3173-
}
3223+
}
3224+
}
31743225

3175-
successful_call
3176-
} else {
3177-
ensure_assignable_to(meta_attr_ty)
3178-
};
3226+
successful_call
3227+
} else {
3228+
ensure_assignable_to(meta_attr_ty)
3229+
};
31793230

3180-
let assignable_to_instance_attribute =
3181-
if meta_attr_boundness == Boundness::PossiblyUnbound {
3182-
let (assignable, boundness) = if let Symbol::Type(
3183-
instance_attr_ty,
3184-
instance_attr_boundness,
3185-
) =
3186-
object_ty.instance_member(db, attribute).symbol
3187-
{
3188-
(
3189-
ensure_assignable_to(instance_attr_ty),
3190-
instance_attr_boundness,
3191-
)
3192-
} else {
3193-
(true, Boundness::PossiblyUnbound)
3194-
};
3231+
let assignable_to_instance_attribute =
3232+
if meta_attr_boundness == Boundness::PossiblyUnbound {
3233+
let (assignable, boundness) = if let Symbol::Type(
3234+
instance_attr_ty,
3235+
instance_attr_boundness,
3236+
) =
3237+
object_ty.instance_member(db, attribute).symbol
3238+
{
3239+
(
3240+
ensure_assignable_to(instance_attr_ty),
3241+
instance_attr_boundness,
3242+
)
3243+
} else {
3244+
(true, Boundness::PossiblyUnbound)
3245+
};
31953246

3196-
if boundness == Boundness::PossiblyUnbound {
3247+
if boundness == Boundness::PossiblyUnbound {
3248+
report_possibly_unbound_attribute(
3249+
&self.context,
3250+
target,
3251+
attribute,
3252+
object_ty,
3253+
);
3254+
}
3255+
3256+
assignable
3257+
} else {
3258+
true
3259+
};
3260+
3261+
assignable_to_meta_attr && assignable_to_instance_attribute
3262+
}
3263+
}
3264+
3265+
SymbolAndQualifiers {
3266+
symbol: Symbol::Unbound,
3267+
..
3268+
} => {
3269+
if let Symbol::Type(instance_attr_ty, instance_attr_boundness) =
3270+
object_ty.instance_member(db, attribute).symbol
3271+
{
3272+
if instance_attr_boundness == Boundness::PossiblyUnbound {
31973273
report_possibly_unbound_attribute(
31983274
&self.context,
31993275
target,
@@ -3202,79 +3278,23 @@ impl<'db> TypeInferenceBuilder<'db> {
32023278
);
32033279
}
32043280

3205-
assignable
3206-
} else {
3207-
true
3208-
};
3209-
3210-
assignable_to_meta_attr && assignable_to_instance_attribute
3211-
}
3212-
}
3213-
3214-
SymbolAndQualifiers {
3215-
symbol: Symbol::Unbound,
3216-
..
3217-
} => {
3218-
if let Symbol::Type(instance_attr_ty, instance_attr_boundness) =
3219-
object_ty.instance_member(db, attribute).symbol
3220-
{
3221-
if instance_attr_boundness == Boundness::PossiblyUnbound {
3222-
report_possibly_unbound_attribute(
3223-
&self.context,
3224-
target,
3225-
attribute,
3226-
object_ty,
3227-
);
3228-
}
3229-
3230-
if is_read_only() {
3231-
if emit_diagnostics {
3232-
if let Some(builder) =
3233-
self.context.report_lint(&INVALID_ASSIGNMENT, target)
3234-
{
3235-
builder.into_diagnostic(format_args!(
3281+
if is_read_only() {
3282+
if emit_diagnostics {
3283+
if let Some(builder) = self
3284+
.context
3285+
.report_lint(&INVALID_ASSIGNMENT, target)
3286+
{
3287+
builder.into_diagnostic(format_args!(
32363288
"Property `{attribute}` defined in `{ty}` is read-only",
32373289
ty = object_ty.display(self.db()),
32383290
));
3239-
}
3240-
}
3241-
false
3242-
} else {
3243-
ensure_assignable_to(instance_attr_ty)
3244-
}
3245-
} else {
3246-
let result = object_ty.try_call_dunder_with_policy(
3247-
db,
3248-
"__setattr__",
3249-
&mut CallArgumentTypes::positional([
3250-
Type::StringLiteral(StringLiteralType::new(
3251-
db,
3252-
Box::from(attribute),
3253-
)),
3254-
value_ty,
3255-
]),
3256-
MemberLookupPolicy::MRO_NO_OBJECT_FALLBACK,
3257-
);
3258-
3259-
match result {
3260-
Ok(_) | Err(CallDunderError::PossiblyUnbound(_)) => true,
3261-
Err(CallDunderError::CallError(..)) => {
3262-
if emit_diagnostics {
3263-
if let Some(builder) =
3264-
self.context.report_lint(&UNRESOLVED_ATTRIBUTE, target)
3265-
{
3266-
builder.into_diagnostic(format_args!(
3267-
"Can not assign object of `{}` to attribute \
3268-
`{attribute}` on type `{}` with \
3269-
custom `__setattr__` method.",
3270-
value_ty.display(db),
3271-
object_ty.display(db)
3272-
));
3291+
}
32733292
}
3293+
false
3294+
} else {
3295+
ensure_assignable_to(instance_attr_ty)
32743296
}
3275-
false
3276-
}
3277-
Err(CallDunderError::MethodNotAvailable) => {
3297+
} else {
32783298
if emit_diagnostics {
32793299
if let Some(builder) =
32803300
self.context.report_lint(&UNRESOLVED_ATTRIBUTE, target)

0 commit comments

Comments
 (0)