Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
24 changes: 24 additions & 0 deletions pyrefly/lib/alt/answers_solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -857,4 +857,28 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
pub fn error_swallower(&self) -> ErrorCollector {
ErrorCollector::new(self.module().dupe(), ErrorStyle::Never)
}

pub fn prefer_union_branch_without_vars(&self, ty: &Type) -> Option<Type> {
if let Type::Union(options) = ty {
let mut reordered = options.clone();
reordered.sort_by_key(|option| self.type_contains_var(option));
if reordered == *options {
None
} else {
Some(Type::Union(reordered))
}
} else {
None
}
}

pub(crate) fn type_contains_var(&self, ty: &Type) -> bool {
let mut has_var = false;
ty.universe(&mut |t| {
if matches!(t, Type::Var(_)) {
has_var = true;
}
});
has_var
}
}
2 changes: 1 addition & 1 deletion pyrefly/lib/alt/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
None,
)
}
})
})
}
}

Expand Down
88 changes: 70 additions & 18 deletions pyrefly/lib/alt/callable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ impl CallArgPreEval<'_> {
solver: &AnswersSolver<Ans>,
callable_name: Option<&FunctionKind>,
hint: &Type,
use_hint: bool,
param_name: Option<&Name>,
vararg: bool,
range: TextRange,
Expand All @@ -334,11 +335,16 @@ impl CallArgPreEval<'_> {
}
Self::Expr(x, done) => {
*done = true;
solver.expr_with_separate_check_errors(
x,
Some((hint, call_errors, tcc)),
arg_errors,
);
if use_hint && !hint.is_any() {
solver.expr_with_separate_check_errors(
x,
Some((hint, call_errors, tcc)),
arg_errors,
);
} else {
let ty = solver.expr_infer(x, arg_errors);
solver.check_type(&ty, hint, range, call_errors, tcc);
}
}
Self::Star(ty, done) => {
*done = vararg;
Expand Down Expand Up @@ -541,17 +547,39 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
// We ignore positional-only parameters because they can't be passed in by name.
seen_names.insert(name, ty);
}
let ty = if let Some(reordered) = self.prefer_union_branch_without_vars(ty)
{
type_owner.push(reordered)
} else {
ty
};
let expanded = self.solver().expand_vars((*ty).clone());
let (hint_ty, mut use_hint) = if expanded == *ty {
(ty, false)
} else {
(type_owner.push(expanded), true)
};
if !use_hint {
if !self.type_contains_var(hint_ty) {
use_hint = true;
} else if let Type::Union(options) = hint_ty {
if options.iter().any(|option| !self.type_contains_var(option)) {
use_hint = true;
}
}
}
arg_pre.post_check(
self,
callable_name,
ty,
hint_ty,
use_hint,
name,
false,
arg.range(),
arg_errors,
call_errors,
context,
)
);
}
Some(PosParam {
ty,
Expand All @@ -568,17 +596,41 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
ty,
name,
kind: PosParamKind::Variadic,
}) => arg_pre.post_check(
self,
callable_name,
ty,
name,
true,
arg.range(),
arg_errors,
call_errors,
context,
),
}) => {
let ty = if let Some(reordered) = self.prefer_union_branch_without_vars(ty)
{
type_owner.push(reordered)
} else {
ty
};
let expanded = self.solver().expand_vars((*ty).clone());
let (hint_ty, mut use_hint) = if expanded == *ty {
(ty, false)
} else {
(type_owner.push(expanded), true)
};
if !use_hint {
if !self.type_contains_var(hint_ty) {
use_hint = true;
} else if let Type::Union(options) = hint_ty {
if options.iter().any(|option| !self.type_contains_var(option)) {
use_hint = true;
}
}
}
arg_pre.post_check(
self,
callable_name,
hint_ty,
use_hint,
name,
true,
arg.range(),
arg_errors,
call_errors,
context,
)
}
None => {
arg_pre.post_infer(self, arg_errors);
if !arg_pre.is_star() {
Expand Down
9 changes: 3 additions & 6 deletions pyrefly/lib/alt/class/typed_dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ use crate::alt::class::class_field::ClassField;
use crate::alt::types::class_metadata::ClassMetadata;
use crate::alt::types::class_metadata::ClassSynthesizedField;
use crate::alt::types::class_metadata::ClassSynthesizedFields;
use crate::alt::unwrap::HintRef;
use crate::binding::binding::ClassFieldDefinition;
use crate::config::error_kind::ErrorKind;
use crate::error::collector::ErrorCollector;
Expand Down Expand Up @@ -149,11 +148,9 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
// This is an unpacked item (`**some_dict`).
has_expansion = true;
let partial_td_ty = Type::PartialTypedDict(typed_dict.clone());
let item_ty = self.expr_infer_with_hint(
&x.value,
Some(HintRef::soft(&partial_td_ty)),
item_errors,
);
let partial_hint = self.hint_from_type(partial_td_ty.clone(), None);
let item_ty =
self.expr_infer_with_hint(&x.value, Some(partial_hint.as_ref()), item_errors);
let subset_result = self.is_subset_eq_with_reason(&item_ty, &partial_td_ty);
if let Some(subset_error) = subset_result.err() {
let tcc: &dyn Fn() -> TypeCheckContext =
Expand Down
Loading