This commit is contained in:
Douglas Creager 2025-11-18 14:53:34 -05:00
parent 336d01957d
commit 6a448e1623
3 changed files with 76 additions and 14 deletions

View File

@ -2891,9 +2891,16 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
// should prefer the tighter specialization.
// XXX: Determine typevar variance per argument
eprintln!(
"--> arg {} {} {}",
argument_index,
argument_constraints.display(self.db),
valid_argument_constraints.display(self.db),
);
constraints.intersect(self.db, valid_argument_constraints);
}
}
eprintln!("--> constraints {}", constraints.display(self.db));
// Attempt to promote any literal types assigned to the specialization.
let maybe_promote = |identity, typevar, ty: Type<'db>| {
@ -2949,15 +2956,23 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
generic_context.specialize_constrained_mapped(self.db, constraints, maybe_promote)
else {
// XXX: better error
eprintln!("--> X1");
return;
};
// XXX: maybe_promote
let isolated_return_ty = self
.return_ty
.apply_specialization(self.db, isolated_specialization);
eprintln!("--> spec {}", isolated_specialization.display_full(self.db));
eprintln!("--> rty {}", isolated_return_ty.display(self.db));
let mut try_infer_tcx = || {
let (return_ty, call_expression_tcx) = return_with_tcx?;
eprintln!(
"--> infer tcx {} {}",
return_ty.display(self.db),
call_expression_tcx.display(self.db)
);
// A type variable is not a useful type-context for expression inference, and applying it
// to the return type can lead to confusing unions in nested generic calls.
@ -2968,6 +2983,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
// If the return type is already assignable to the annotated type, we ignore the rest of
// the type context and prefer the narrower inferred type.
if isolated_return_ty.is_assignable_to(self.db, call_expression_tcx) {
eprintln!("--> X2");
return None;
}
@ -2977,6 +2993,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
.when_assignable_to(self.db, call_expression_tcx, self.inferable_typevars)
.and(self.db, || valid_specializations);
if return_constraints.is_never_satisfied(self.db) {
eprintln!("--> X3");
return None;
}
@ -2987,6 +3004,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
maybe_promote,
) else {
// XXX: better return
eprintln!("--> X4");
return None;
};
// XXX: maybe_promote
@ -3009,13 +3027,37 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
let parameters = self.signature.parameters();
let parameter = &parameters[parameter_index];
if let Some(mut expected_ty) = parameter.annotated_type() {
eprintln!(
"--> before {:?} {} {}",
adjusted_argument_index,
argument_type.display(self.db),
expected_ty.display(self.db),
);
if let Some(specialization) = self.specialization {
argument_type = argument_type.apply_specialization(self.db, specialization);
expected_ty = expected_ty.apply_specialization(self.db, specialization);
eprintln!(
"--> after {:?} {} {}",
adjusted_argument_index,
argument_type.display(self.db),
expected_ty.display(self.db),
);
eprintln!(" {:?}", argument_type);
eprintln!(" {:?}", expected_ty);
}
// TODO: Soon we will go further, and build the actual specializations from the
// constraint set that we get from this assignability check, instead of inferring and
// building them in an earlier separate step.
let when =
argument_type.when_assignable_to(self.db, expected_ty, self.inferable_typevars);
eprintln!("===> check argument");
eprintln!(" --> arg {}", argument_type.display(self.db));
eprintln!(" --> param {}", expected_ty.display(self.db));
eprintln!(" --> when {}", when.display(self.db));
eprintln!(
" --> sat {}",
when.satisfied_by_all_typevars(self.db, self.inferable_typevars)
);
if !argument_type
.when_assignable_to(self.db, expected_ty, self.inferable_typevars)
.satisfied_by_all_typevars(self.db, self.inferable_typevars)

View File

@ -1432,6 +1432,7 @@ impl<'db> SpecializationBuilder<'db> {
mut f: &mut dyn FnMut(TypeVarAssignment<'db>) -> Option<Type<'db>>,
) -> Result<(), SpecializationError<'db>> {
if formal == actual {
eprintln!(" --> AAA");
return Ok(());
}
@ -1510,6 +1511,7 @@ impl<'db> SpecializationBuilder<'db> {
.satisfied_by_all_typevars(self.db, InferableTypeVars::None)
});
if assignable_elements.exactly_one().is_ok() {
eprintln!(" --> BBB");
return Ok(());
}
}

View File

@ -876,19 +876,22 @@ impl<'db> Signature<'db> {
let mut check_types = |type1: Option<Type<'db>>, type2: Option<Type<'db>>| {
let type1 = type1.unwrap_or(Type::unknown());
let type2 = type2.unwrap_or(Type::unknown());
!result
.intersect(
db,
type1.has_relation_to_impl(
eprintln!(" --> check param");
eprintln!(" {}", type1.display(db));
eprintln!(" {}", type2.display(db));
let x = type1.has_relation_to_impl(
db,
type2,
inferable,
relation,
relation_visitor,
disjointness_visitor,
),
)
.is_never_satisfied(db)
);
eprintln!(" x {}", x.display(db),);
let y = result.intersect(db, x);
eprintln!(" y {}", y.display(db),);
eprintln!(" ? {}", !y.is_never_satisfied(db));
!y.is_never_satisfied(db)
};
// Return types are covariant.
@ -932,6 +935,7 @@ impl<'db> Signature<'db> {
let Some(next_parameter) = parameters.next() else {
// All parameters have been checked or both the parameter lists were empty. In
// either case, `self` is a subtype of `other`.
eprintln!(" --> X1 {}", result.display(db));
return result;
};
@ -952,6 +956,7 @@ impl<'db> Signature<'db> {
// `other`, then the non-variadic parameters in `self` must have a default
// value.
if default_type.is_none() {
eprintln!(" --> X2");
return ConstraintSet::from(false);
}
}
@ -964,6 +969,7 @@ impl<'db> Signature<'db> {
EitherOrBoth::Right(_) => {
// If there are more parameters in `other` than in `self`, then `self` is not a
// subtype of `other`.
eprintln!(" --> X3");
return ConstraintSet::from(false);
}
@ -984,12 +990,14 @@ impl<'db> Signature<'db> {
},
) => {
if self_default.is_none() && other_default.is_some() {
eprintln!(" --> X4");
return ConstraintSet::from(false);
}
if !check_types(
other_parameter.annotated_type(),
self_parameter.annotated_type(),
) {
eprintln!(" --> X5");
return result;
}
}
@ -1005,16 +1013,19 @@ impl<'db> Signature<'db> {
},
) => {
if self_name != other_name {
eprintln!(" --> X6");
return ConstraintSet::from(false);
}
// The following checks are the same as positional-only parameters.
if self_default.is_none() && other_default.is_some() {
eprintln!(" --> X7");
return ConstraintSet::from(false);
}
if !check_types(
other_parameter.annotated_type(),
self_parameter.annotated_type(),
) {
eprintln!(" --> X8");
return result;
}
}
@ -1028,6 +1039,7 @@ impl<'db> Signature<'db> {
other_parameter.annotated_type(),
self_parameter.annotated_type(),
) {
eprintln!(" --> X9");
return result;
}
@ -1068,6 +1080,7 @@ impl<'db> Signature<'db> {
other_parameter.annotated_type(),
self_parameter.annotated_type(),
) {
eprintln!(" --> X10");
return result;
}
parameters.next_other();
@ -1079,6 +1092,7 @@ impl<'db> Signature<'db> {
other_parameter.annotated_type(),
self_parameter.annotated_type(),
) {
eprintln!(" --> X11");
return result;
}
}
@ -1094,12 +1108,16 @@ impl<'db> Signature<'db> {
break;
}
_ => return ConstraintSet::from(false),
_ => {
eprintln!(" --> X12");
return ConstraintSet::from(false);
}
}
}
}
}
eprintln!(" --> YYY");
// At this point, the remaining parameters in `other` are keyword-only or keyword variadic.
// But, `self` could contain any unmatched positional parameters.
let (self_parameters, other_parameters) = parameters.into_remaining();