error message

This commit is contained in:
Douglas Creager 2025-12-15 14:38:54 -05:00
parent 9b5709f34b
commit d94b2d3578
2 changed files with 62 additions and 19 deletions

View File

@ -4445,7 +4445,6 @@ impl<'db> BindingError<'db> {
return; return;
}; };
let typevar = error.bound_typevar().typevar(context.db());
let argument_type = error.argument_type(); let argument_type = error.argument_type();
let argument_ty_display = argument_type.display(context.db()); let argument_ty_display = argument_type.display(context.db());
@ -4458,21 +4457,51 @@ impl<'db> BindingError<'db> {
} }
)); ));
let typevar_name = typevar.name(context.db());
match error { match error {
SpecializationError::MismatchedBound { .. } => { SpecializationError::NoSolution { parameter, .. } => {
diag.set_primary_message(format_args!("Argument type `{argument_ty_display}` does not satisfy upper bound `{}` of type variable `{typevar_name}`", diag.set_primary_message(format_args!(
typevar.upper_bound(context.db()).expect("type variable should have an upper bound if this error occurs").display(context.db()) "Argument type `{argument_ty_display}` does not \
)); satisfy generic parameter annotation `{}",
parameter.display(context.db()),
));
} }
SpecializationError::MismatchedConstraint { .. } => { SpecializationError::MismatchedBound { bound_typevar, .. } => {
diag.set_primary_message(format_args!("Argument type `{argument_ty_display}` does not satisfy constraints ({}) of type variable `{typevar_name}`", let typevar = bound_typevar.typevar(context.db());
typevar.constraints(context.db()).expect("type variable should have constraints if this error occurs").iter().map(|ty| format!("`{}`", ty.display(context.db()))).join(", ") let typevar_name = typevar.name(context.db());
)); diag.set_primary_message(format_args!(
"Argument type `{argument_ty_display}` does not \
satisfy upper bound `{}` of type variable `{typevar_name}`",
typevar
.upper_bound(context.db())
.expect(
"type variable should have an upper bound if this error occurs"
)
.display(context.db())
));
}
SpecializationError::MismatchedConstraint { bound_typevar, .. } => {
let typevar = bound_typevar.typevar(context.db());
let typevar_name = typevar.name(context.db());
diag.set_primary_message(format_args!(
"Argument type `{argument_ty_display}` does not \
satisfy constraints ({}) of type variable `{typevar_name}`",
typevar
.constraints(context.db())
.expect(
"type variable should have constraints if this error occurs"
)
.iter()
.format_with(", ", |ty, f| f(&format_args!(
"`{}`",
ty.display(context.db())
)))
));
} }
} }
if let Some(typevar_definition) = typevar.definition(context.db()) { if let Some(typevar_definition) = error.bound_typevar().and_then(|bound_typevar| {
bound_typevar.typevar(context.db()).definition(context.db())
}) {
let module = parsed_module(context.db(), typevar_definition.file(context.db())) let module = parsed_module(context.db(), typevar_definition.file(context.db()))
.load(context.db()); .load(context.db());
let typevar_range = typevar_definition.full_range(context.db(), &module); let typevar_range = typevar_definition.full_range(context.db(), &module);

View File

@ -1587,7 +1587,6 @@ impl<'db> SpecializationBuilder<'db> {
upper: Vec<Type<'db>>, upper: Vec<Type<'db>>,
} }
let constraints = constraints.limit_to_valid_specializations(self.db);
let mut sorted_paths = Vec::new(); let mut sorted_paths = Vec::new();
constraints.for_each_path(self.db, |path| { constraints.for_each_path(self.db, |path| {
let mut path: Vec<_> = path.positive_constraints().collect(); let mut path: Vec<_> = path.positive_constraints().collect();
@ -1884,8 +1883,15 @@ impl<'db> SpecializationBuilder<'db> {
return Ok(()); return Ok(());
} }
let when = let when = actual
actual.when_constraint_set_assignable_to(self.db, formal, self.inferable); .when_constraint_set_assignable_to(self.db, formal, self.inferable)
.limit_to_valid_specializations(self.db);
if when.is_never_satisfied(self.db) {
return Err(SpecializationError::NoSolution {
parameter: formal,
argument: actual,
});
}
self.add_type_mappings_from_constraint_set(formal, when, &mut f); self.add_type_mappings_from_constraint_set(formal, when, &mut f);
} }
@ -1905,7 +1911,8 @@ impl<'db> SpecializationBuilder<'db> {
self.db, self.db,
formal_callable, formal_callable,
self.inferable, self.inferable,
); )
.limit_to_valid_specializations(self.db);
self.add_type_mappings_from_constraint_set(formal, when, &mut f); self.add_type_mappings_from_constraint_set(formal, when, &mut f);
} else { } else {
for actual_signature in &actual_callable.signatures(self.db).overloads { for actual_signature in &actual_callable.signatures(self.db).overloads {
@ -1914,7 +1921,8 @@ impl<'db> SpecializationBuilder<'db> {
self.db, self.db,
formal_callable, formal_callable,
self.inferable, self.inferable,
); )
.limit_to_valid_specializations(self.db);
self.add_type_mappings_from_constraint_set(formal, when, &mut f); self.add_type_mappings_from_constraint_set(formal, when, &mut f);
} }
} }
@ -1931,6 +1939,10 @@ impl<'db> SpecializationBuilder<'db> {
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) enum SpecializationError<'db> { pub(crate) enum SpecializationError<'db> {
NoSolution {
parameter: Type<'db>,
argument: Type<'db>,
},
MismatchedBound { MismatchedBound {
bound_typevar: BoundTypeVarInstance<'db>, bound_typevar: BoundTypeVarInstance<'db>,
argument: Type<'db>, argument: Type<'db>,
@ -1942,15 +1954,17 @@ pub(crate) enum SpecializationError<'db> {
} }
impl<'db> SpecializationError<'db> { impl<'db> SpecializationError<'db> {
pub(crate) fn bound_typevar(&self) -> BoundTypeVarInstance<'db> { pub(crate) fn bound_typevar(&self) -> Option<BoundTypeVarInstance<'db>> {
match self { match self {
Self::MismatchedBound { bound_typevar, .. } => *bound_typevar, Self::NoSolution { .. } => None,
Self::MismatchedConstraint { bound_typevar, .. } => *bound_typevar, Self::MismatchedBound { bound_typevar, .. } => Some(*bound_typevar),
Self::MismatchedConstraint { bound_typevar, .. } => Some(*bound_typevar),
} }
} }
pub(crate) fn argument_type(&self) -> Type<'db> { pub(crate) fn argument_type(&self) -> Type<'db> {
match self { match self {
Self::NoSolution { argument, .. } => *argument,
Self::MismatchedBound { argument, .. } => *argument, Self::MismatchedBound { argument, .. } => *argument,
Self::MismatchedConstraint { argument, .. } => *argument, Self::MismatchedConstraint { argument, .. } => *argument,
} }