Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/source_analyzer.rs')
| -rw-r--r-- | crates/hir/src/source_analyzer.rs | 67 |
1 files changed, 57 insertions, 10 deletions
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 1f9520d780..687f130af4 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -13,10 +13,10 @@ use std::{ use either::Either; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, ExpressionStoreOwnerId, FieldId, - FunctionId, GenericDefId, LocalFieldId, ModuleDefId, StructId, VariantId, + FunctionId, GenericDefId, HasModule, LocalFieldId, ModuleDefId, StructId, VariantId, expr_store::{ Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, HygieneId, - lower::ExprCollector, + lower::{ExprCollector, lower_generic_params}, path::Path, scope::{ExprScopes, ScopeId}, }, @@ -44,7 +44,7 @@ use hir_ty::{ AliasTy, DbInterner, DefaultAny, EarlyBinder, ErrorGuaranteed, GenericArgs, ParamEnv, Region, Ty, TyKind, TypingMode, infer::DbInternerInferExt, }, - traits::structurally_normalize_ty, + traits::{WherePredicateEvaluation, structurally_normalize_ty, where_predicate_must_hold}, }; use intern::sym; use itertools::Itertools; @@ -63,7 +63,8 @@ use syntax::{ use crate::{ Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, EnumVariant, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, - SemanticsImpl, Static, Struct, ToolModule, Trait, TupleField, Type, TypeAlias, TypeOwnerId, + PredicateEvaluationResult, SemanticsImpl, Static, Struct, ToolModule, Trait, TupleField, Type, + TypeAlias, TypeOwnerId, db::HirDatabase, semantics::{PathResolution, PathResolutionPerNs}, }; @@ -364,6 +365,52 @@ impl<'db> SourceAnalyzer<'db> { )) } + pub(crate) fn evaluate_where_clause( + &self, + db: &'db dyn HirDatabase, + where_clause: ast::WhereClause, + ) -> PredicateEvaluationResult { + let Some(owner) = self.owner() else { + // FIXME + return PredicateEvaluationResult::unsupported( + "predicate evaluation is only supported inside an item", + ); + }; + let generic_def = owner.generic_def(db); + let module = generic_def.module(db); + let (store, params, _) = + lower_generic_params(db, module, generic_def, self.file_id, None, Some(where_clause)); + let predicates = params.where_predicates(); + if predicates.is_empty() { + return PredicateEvaluationResult::holds("predicate does not impose any obligations"); + } + + let env = self.trait_environment(db); + for predicate in predicates { + match where_predicate_must_hold( + db, + &self.resolver, + &store, + owner, + generic_def, + env, + predicate, + ) { + WherePredicateEvaluation::Holds | WherePredicateEvaluation::NoObligations => {} + WherePredicateEvaluation::HasErrors => { + return PredicateEvaluationResult::invalid( + "predicate contains unresolved names or invalid type syntax", + ); + } + WherePredicateEvaluation::NotProven => { + return PredicateEvaluationResult::not_proven("predicate is not known to hold"); + } + } + } + + PredicateEvaluationResult::holds("predicate holds") + } + pub(crate) fn expr_id(&self, expr: ast::Expr) -> Option<ExprOrPatId> { let src = InFile { file_id: self.file_id, value: expr }; self.store_sm()?.node_expr(src.as_ref()) @@ -927,7 +974,7 @@ impl<'db> SourceAnalyzer<'db> { let variant_data = variant.fields(db); let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; let field_ty = (*db.field_types(variant).get(field.local_id)?) - .get() + .ty() .instantiate(interner, subst) .skip_norm_wip(); Some(( @@ -952,7 +999,7 @@ impl<'db> SourceAnalyzer<'db> { let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? }; let (adt, subst) = self.infer()?.pat_ty(pat_id.as_pat()?).as_adt()?; let field_ty = (*db.field_types(variant).get(field.local_id)?) - .get() + .ty() .instantiate(interner, subst) .skip_norm_wip(); Some(( @@ -975,9 +1022,9 @@ impl<'db> SourceAnalyzer<'db> { Some( db.field_types(variant_id) .iter() - .map(|(local_id, ty)| { + .map(|(local_id, field)| { let def = Field { parent: variant_id.into(), id: local_id }; - let ty = ty.get().instantiate(interner, substs).skip_norm_wip(); + let ty = field.ty().instantiate(interner, substs).skip_norm_wip(); (def, self.ty(ty)) }) .collect(), @@ -1051,7 +1098,7 @@ impl<'db> SourceAnalyzer<'db> { let field = fields.field(&field_name.as_name())?; let field_types = db.field_types(variant); *container = Either::Right( - field_types[field].get().instantiate(interner, subst).skip_norm_wip(), + field_types[field].ty().instantiate(interner, subst).skip_norm_wip(), ); let generic_def = match variant { VariantId::EnumVariantId(it) => it.loc(db).parent.into(), @@ -1530,7 +1577,7 @@ impl<'db> SourceAnalyzer<'db> { .into_iter() .map(|local_id| { let field = FieldId { parent: variant, local_id }; - let ty = field_types[local_id].get().instantiate(interner, substs).skip_norm_wip(); + let ty = field_types[local_id].ty().instantiate(interner, substs).skip_norm_wip(); (field.into(), self.ty(ty)) }) .collect() |