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.rs | 98 |
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(); |