Skip to main content

hir_ty/
solver_errors.rs

1//! Handling of trait solver errors and converting them to errors `hir` can pass to `ide-diagnostics`.
2//!
3//! Note that we also have [`crate::next_solver::infer::errors`], which takes the raw [`NextSolverError`],
4//! and converts it into [`FulfillmentError`] that contains more details.
5//!
6//! [`NextSolverError`]: crate::next_solver::fulfill::NextSolverError
7
8use macros::{TypeFoldable, TypeVisitable};
9use rustc_type_ir::{PredicatePolarity, inherent::IntoKind};
10
11use crate::{
12    Span,
13    next_solver::{
14        ClauseKind, DbInterner, PredicateKind, StoredTraitRef, TraitPredicate,
15        infer::{
16            errors::{FulfillmentError, FulfillmentErrorCode},
17            select::SelectionError,
18        },
19    },
20};
21
22#[derive(Debug, Clone, PartialEq, Eq, TypeVisitable, TypeFoldable)]
23pub struct SolverDiagnostic {
24    pub span: Span,
25    pub kind: SolverDiagnosticKind,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, TypeVisitable, TypeFoldable)]
29pub enum SolverDiagnosticKind {
30    TraitUnimplemented {
31        trait_predicate: StoredTraitPredicate,
32        parent_trait_predicates: Vec<StoredTraitPredicate>,
33    },
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, TypeVisitable, TypeFoldable)]
37pub struct StoredTraitPredicate {
38    pub trait_ref: StoredTraitRef,
39    pub polarity: PredicatePolarity,
40}
41
42impl StoredTraitPredicate {
43    #[inline]
44    pub fn get<'db>(&'db self, interner: DbInterner<'db>) -> TraitPredicate<'db> {
45        TraitPredicate { polarity: self.polarity, trait_ref: self.trait_ref.get(interner) }
46    }
47}
48
49impl SolverDiagnostic {
50    pub fn from_fulfillment_error(error: &FulfillmentError<'_>) -> Option<Self> {
51        let span = error.obligation.cause.span();
52        if span.is_dummy() {
53            return None;
54        }
55
56        // FIXME: Handle more error kinds.
57        let kind = match &error.code {
58            FulfillmentErrorCode::Select(SelectionError::Unimplemented) => {
59                match error.obligation.predicate.kind().skip_binder() {
60                    PredicateKind::Clause(ClauseKind::Trait(trait_pred)) => {
61                        handle_trait_unimplemented(error, trait_pred)?
62                    }
63                    _ => return None,
64                }
65            }
66            _ => return None,
67        };
68        Some(SolverDiagnostic { span, kind })
69    }
70}
71
72fn handle_trait_unimplemented<'db>(
73    error: &FulfillmentError<'db>,
74    trait_pred: TraitPredicate<'db>,
75) -> Option<SolverDiagnosticKind> {
76    let trait_predicate = StoredTraitPredicate {
77        trait_ref: StoredTraitRef::new(trait_pred.trait_ref),
78        polarity: trait_pred.polarity,
79    };
80
81    let mut parent_trait_predicates = error
82        .parent_trait_obligations
83        .iter()
84        .filter_map(|predicate| predicate.as_trait_clause())
85        .map(|trait_predicate| {
86            let trait_predicate = trait_predicate.skip_binder();
87            StoredTraitPredicate {
88                trait_ref: StoredTraitRef::new(trait_predicate.trait_ref),
89                polarity: trait_predicate.polarity,
90            }
91        })
92        .collect::<Vec<_>>();
93    parent_trait_predicates.reverse();
94
95    Some(SolverDiagnosticKind::TraitUnimplemented { trait_predicate, parent_trait_predicates })
96}