Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/traits.rs')
-rw-r--r--crates/hir-ty/src/traits.rs98
1 files changed, 94 insertions, 4 deletions
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index f6b5adfb6f..4c76ae901d 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -1,12 +1,15 @@
//! Trait solving using next trait solver.
-use std::hash::Hash;
+use std::{cell::OnceCell, hash::Hash};
use base_db::Crate;
use hir_def::{
- AdtId, AssocItemId, HasModule, ImplId, Lookup, TraitId,
+ AdtId, AssocItemId, ExpressionStoreOwnerId, GenericDefId, HasModule, ImplId, Lookup, TraitId,
+ expr_store::ExpressionStore,
+ hir::generics::WherePredicate,
lang_item::LangItems,
nameres::DefMap,
+ resolver::Resolver,
signatures::{
ConstFlags, ConstSignature, EnumFlags, EnumSignature, FnFlags, FunctionSignature,
StructFlags, StructSignature, TraitFlags, TraitSignature, TypeAliasFlags,
@@ -16,17 +19,20 @@ use hir_def::{
use hir_expand::name::Name;
use intern::sym;
use rustc_type_ir::{
- TypingMode,
+ TypeVisitableExt, TypingMode,
inherent::{BoundExistentialPredicates, IntoKind},
};
use crate::{
- Span,
+ LifetimeElisionKind, Span, TyLoweringContext,
db::HirDatabase,
+ generics::Generics,
+ lower::LoweringMode,
next_solver::{
DbInterner, GenericArgs, ParamEnv, StoredClauses, Ty, TyKind,
infer::{
DbInternerInferExt, InferCtxt,
+ select::EvaluationResult,
traits::{Obligation, ObligationCause},
},
obligation_ctxt::ObligationCtxt,
@@ -153,6 +159,90 @@ pub fn implements_trait_unique_with_infcx<'db>(
infcx.predicate_must_hold_modulo_regions(&obligation)
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum WherePredicateEvaluation {
+ Holds,
+ NotProven,
+ HasErrors,
+ NoObligations,
+}
+
+/// This should not be used in `hir-ty`, only in `hir`.
+/// This is exposed to allow the IDE to evaluate arbitrary predicates.
+pub fn where_predicate_must_hold<'db>(
+ db: &'db dyn HirDatabase,
+ resolver: &Resolver<'db>,
+ store: &ExpressionStore,
+ def: ExpressionStoreOwnerId,
+ generic_def: GenericDefId,
+ env: ParamEnvAndCrate<'db>,
+ predicate: &WherePredicate,
+) -> WherePredicateEvaluation {
+ let interner = DbInterner::new_with(db, env.krate);
+ let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
+ let generics = OnceCell::<Generics<'db>>::new();
+ let mut ctx = TyLoweringContext::new(
+ db,
+ resolver,
+ store,
+ def,
+ generic_def,
+ &generics,
+ LifetimeElisionKind::Infer,
+ )
+ .with_interning_mode(LoweringMode::Ide);
+ let clauses =
+ ctx.lower_where_predicate(predicate, false).map(|(clause, _)| clause).collect::<Vec<_>>();
+
+ if !ctx.diagnostics.is_empty()
+ || clauses.iter().any(|clause| clause.as_predicate().references_error())
+ {
+ return WherePredicateEvaluation::HasErrors;
+ }
+
+ if clauses.is_empty() {
+ return if ctx.unsized_types.is_empty() {
+ WherePredicateEvaluation::HasErrors
+ } else {
+ WherePredicateEvaluation::NoObligations
+ };
+ }
+
+ let result = infcx.probe(|snapshot| {
+ let mut ocx = ObligationCtxt::new(&infcx);
+ for clause in clauses {
+ let obligation = Obligation::new(
+ interner,
+ ObligationCause::dummy(),
+ env.param_env,
+ clause.as_predicate(),
+ );
+ ocx.register_obligation(obligation);
+ }
+
+ let mut result = EvaluationResult::EvaluatedToOk;
+ for error in ocx.evaluate_obligations_error_on_ambiguity() {
+ if error.is_true_error() {
+ return EvaluationResult::EvaluatedToErr;
+ }
+ result = result.max(EvaluationResult::EvaluatedToAmbig);
+ }
+ if infcx.opaque_types_added_in_snapshot(snapshot) {
+ result.max(EvaluationResult::EvaluatedToOkModuloOpaqueTypes)
+ } else if infcx.region_constraints_added_in_snapshot(snapshot) {
+ result.max(EvaluationResult::EvaluatedToOkModuloRegions)
+ } else {
+ result
+ }
+ });
+
+ if result.must_apply_modulo_regions() {
+ WherePredicateEvaluation::Holds
+ } else {
+ WherePredicateEvaluation::NotProven
+ }
+}
+
pub fn is_inherent_impl_coherent(db: &dyn HirDatabase, def_map: &DefMap, impl_id: ImplId) -> bool {
let self_ty = db.impl_self_ty(impl_id).instantiate_identity().skip_norm_wip();
let self_ty = self_ty.kind();