Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/path.rs')
| -rw-r--r-- | crates/hir-ty/src/infer/path.rs | 230 |
1 files changed, 106 insertions, 124 deletions
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 733f3c2788..f70ed90b95 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -1,52 +1,50 @@ //! Path expression resolution. -use chalk_ir::cast::Cast; use hir_def::{ AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup, expr_store::path::{Path, PathSegment}, resolver::{ResolveValueResult, TypeNs, ValueNs}, }; use hir_expand::name::Name; +use rustc_type_ir::inherent::{SliceLike, Ty as _}; use stdx::never; use crate::{ - InferenceDiagnostic, Interner, LifetimeElisionKind, Substitution, TraitRef, TraitRefExt, Ty, - TyBuilder, TyExt, TyKind, ValueTyDefId, - builder::ParamKind, - consteval, error_lifetime, + InferenceDiagnostic, ValueTyDefId, generics::generics, infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, + lower_nextsolver::LifetimeElisionKind, method_resolution::{self, VisibleFromModule}, next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, NextSolverToChalk}, + GenericArg, GenericArgs, TraitRef, Ty, + infer::traits::{Obligation, ObligationCause}, }, - to_chalk_trait_id, }; use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; -impl<'db> InferenceContext<'db> { - pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty> { +impl<'db> InferenceContext<'_, 'db> { + pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty<'db>> { let (value_def, generic_def, substs) = match self.resolve_value_path(path, id)? { ValuePathResolution::GenericDef(value_def, generic_def, substs) => { (value_def, generic_def, substs) } ValuePathResolution::NonGeneric(ty) => return Some(ty), }; - let substs = - self.process_remote_user_written_ty::<_, crate::next_solver::GenericArgs<'db>>(substs); + let args = self.process_remote_user_written_ty(substs); - self.add_required_obligations_for_value_path(generic_def, &substs); + self.add_required_obligations_for_value_path(generic_def, args); - let interner = DbInterner::new_with(self.db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let ty = self.db.value_ty(value_def)?.instantiate(interner, args).to_chalk(interner); + let ty = self.db.value_ty(value_def)?.instantiate(self.interner(), args); let ty = self.process_remote_user_written_ty(ty); Some(ty) } - fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> { + fn resolve_value_path( + &mut self, + path: &Path, + id: ExprOrPatId, + ) -> Option<ValuePathResolution<'db>> { let (value, self_subst) = self.resolve_value_path_inner(path, id, false)?; let value_def: ValueTyDefId = match value { @@ -65,7 +63,7 @@ impl<'db> InferenceContext<'db> { } ValueNs::LocalBinding(pat) => { return match self.result.type_of_binding.get(pat) { - Some(ty) => Some(ValuePathResolution::NonGeneric(ty.clone())), + Some(ty) => Some(ValuePathResolution::NonGeneric(*ty)), None => { never!("uninferred pattern?"); None @@ -73,17 +71,12 @@ impl<'db> InferenceContext<'db> { }; } ValueNs::ImplSelf(impl_id) => { - let generics = crate::generics::generics(self.db, impl_id.into()); - let interner = DbInterner::new_with(self.db, None, None); - let substs = generics.placeholder_subst(self.db); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let ty = - self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner); + let ty = self.db.impl_self_ty(impl_id).instantiate_identity(); return if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { Some(ValuePathResolution::GenericDef( struct_id.into(), struct_id.into(), - substs.clone(), + substs, )) } else { // FIXME: report error, invalid Self reference @@ -91,67 +84,42 @@ impl<'db> InferenceContext<'db> { }; } ValueNs::GenericParam(it) => { - return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty(it))); + return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty_ns(it))); } }; let generic_def = value_def.to_generic_def_id(self.db); if let GenericDefId::StaticId(_) = generic_def { - let interner = DbInterner::new_with(self.db, None, None); // `Static` is the kind of item that can never be generic currently. We can just skip the binders to get its type. - let ty = self.db.value_ty(value_def)?.skip_binder().to_chalk(interner); + let ty = self.db.value_ty(value_def)?.skip_binder(); return Some(ValuePathResolution::NonGeneric(ty)); }; - let substs = self.with_body_ty_lowering(|ctx| { - let mut path_ctx = ctx.at_path(path, id); - let last_segment = path.segments().len().checked_sub(1); - if let Some(last_segment) = last_segment { - path_ctx.set_current_segment(last_segment) - } - path_ctx.substs_from_path(value_def, true, false) - }); - let substs = substs.as_slice(Interner); - - if let ValueNs::EnumVariantId(_) = value { - let mut it = substs - .iter() - .chain(self_subst.as_ref().map_or(&[][..], |s| s.as_slice(Interner))) - .cloned(); - let builder = TyBuilder::subst_for_def(self.db, generic_def, None); - let substs = builder - .fill(|x| { - it.next().unwrap_or_else(|| match x { - ParamKind::Type => { - self.result.standard_types.unknown.clone().cast(Interner) - } - ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }) - }) - .build(); - - return Some(ValuePathResolution::GenericDef(value_def, generic_def, substs)); - } - - let parent_substs = self_subst.or_else(|| { - let generics = generics(self.db, generic_def); - let parent_params_len = generics.parent_generics()?.len(); - let parent_args = &substs[..parent_params_len]; - Some(Substitution::from_iter(Interner, parent_args)) - }); - let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner)); - let mut it = substs.iter().skip(parent_substs_len).cloned(); - let builder = TyBuilder::subst_for_def(self.db, generic_def, parent_substs); - let substs = builder - .fill(|x| { - it.next().unwrap_or_else(|| match x { - ParamKind::Type => self.result.standard_types.unknown.clone().cast(Interner), - ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }) + let substs = if self_subst.is_some_and(|it| !it.is_empty()) + && matches!(value_def, ValueTyDefId::EnumVariantId(_)) + { + // This is something like `TypeAlias::<Args>::EnumVariant`. Do not call `substs_from_path()`, + // as it'll try to re-lower the previous segment assuming it refers to the enum, but it refers + // to the type alias and they may have different generics. + self.types.empty_args + } else { + self.with_body_ty_lowering(|ctx| { + let mut path_ctx = ctx.at_path(path, id); + let last_segment = path.segments().len().checked_sub(1); + if let Some(last_segment) = last_segment { + path_ctx.set_current_segment(last_segment) + } + path_ctx.substs_from_path(value_def, true, false) }) - .build(); + }; + + let parent_substs_len = self_subst.map_or(0, |it| it.len()); + let substs = GenericArgs::fill_rest( + self.interner(), + generic_def.into(), + self_subst.iter().flat_map(|it| it.iter()).chain(substs.iter().skip(parent_substs_len)), + |_, _, id, _| GenericArg::error_from_id(self.interner(), id), + ); Some(ValuePathResolution::GenericDef(value_def, generic_def, substs)) } @@ -161,7 +129,7 @@ impl<'db> InferenceContext<'db> { path: &Path, id: ExprOrPatId, no_diagnostics: bool, - ) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> { + ) -> Option<(ValueNs, Option<GenericArgs<'db>>)> { // Don't use `self.make_ty()` here as we need `orig_ns`. let mut ctx = TyLoweringContext::new( self.db, @@ -211,7 +179,7 @@ impl<'db> InferenceContext<'db> { let (resolution, substs) = match (def, is_before_last) { (TypeNs::TraitId(trait_), true) => { - let self_ty = self.table.new_type_var(); + let self_ty = self.table.next_ty_var(); let trait_ref = path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty, true); drop_ctx(ctx, no_diagnostics); @@ -225,7 +193,7 @@ impl<'db> InferenceContext<'db> { path_ctx.ignore_last_segment(); let (ty, _) = path_ctx.lower_partly_resolved_path(def, true); drop_ctx(ctx, no_diagnostics); - if ty.is_unknown() { + if ty.is_ty_error() { return None; } @@ -241,21 +209,25 @@ impl<'db> InferenceContext<'db> { return Some((value, self_subst)); #[inline] - fn drop_ctx(mut ctx: TyLoweringContext<'_>, no_diagnostics: bool) { + fn drop_ctx(mut ctx: TyLoweringContext<'_, '_>, no_diagnostics: bool) { if no_diagnostics { ctx.forget_diagnostics(); } } } - fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) { - let predicates = self.db.generic_predicates(def); - for predicate in predicates.iter() { - let (predicate, binders) = - predicate.clone().substitute(Interner, &subst).into_value_and_skipped_binders(); - // Quantified where clauses are not yet handled. - stdx::always!(binders.is_empty(Interner)); - self.push_obligation(predicate.cast(Interner)); + fn add_required_obligations_for_value_path( + &mut self, + def: GenericDefId, + subst: GenericArgs<'db>, + ) { + let predicates = self.db.generic_predicates_ns(def); + let interner = self.interner(); + let param_env = self.table.trait_env.env; + if let Some(predicates) = predicates.instantiate(self.interner(), subst) { + self.table.register_predicates(predicates.map(|predicate| { + Obligation::new(interner, ObligationCause::new(), param_env, predicate) + })); } // We need to add `Self: Trait` obligation when `def` is a trait assoc item. @@ -267,21 +239,27 @@ impl<'db> InferenceContext<'db> { if let ItemContainerId::TraitId(trait_) = container { let parent_len = generics(self.db, def).parent_generics().map_or(0, |g| g.len_self()); - let parent_subst = - Substitution::from_iter(Interner, subst.iter(Interner).take(parent_len)); - let trait_ref = - TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: parent_subst }; - self.push_obligation(trait_ref.cast(Interner)); + let parent_subst = GenericArgs::new_from_iter( + interner, + subst.as_slice()[..parent_len].iter().copied(), + ); + let trait_ref = TraitRef::new(interner, trait_.into(), parent_subst); + self.table.register_predicate(Obligation::new( + interner, + ObligationCause::new(), + param_env, + trait_ref, + )); } } fn resolve_trait_assoc_item( &mut self, - trait_ref: TraitRef, + trait_ref: TraitRef<'db>, segment: PathSegment<'_>, id: ExprOrPatId, - ) -> Option<(ValueNs, Substitution)> { - let trait_ = trait_ref.hir_trait_id(); + ) -> Option<(ValueNs, GenericArgs<'db>)> { + let trait_ = trait_ref.def_id.0; let item = trait_.trait_items(self.db).items.iter().map(|(_name, id)| *id).find_map(|item| { match item { @@ -309,25 +287,25 @@ impl<'db> InferenceContext<'db> { AssocItemId::TypeAliasId(_) => unreachable!(), }; - self.write_assoc_resolution(id, item, trait_ref.substitution.clone()); - Some((def, trait_ref.substitution)) + self.write_assoc_resolution(id, item, trait_ref.args); + Some((def, trait_ref.args)) } fn resolve_ty_assoc_item( &mut self, - ty: Ty, + ty: Ty<'db>, name: &Name, id: ExprOrPatId, - ) -> Option<(ValueNs, Substitution)> { - if let TyKind::Error = ty.kind(Interner) { + ) -> Option<(ValueNs, GenericArgs<'db>)> { + if ty.is_ty_error() { return None; } - if let Some(result) = self.resolve_enum_variant_on_ty(&ty, name, id) { + if let Some(result) = self.resolve_enum_variant_on_ty(ty, name, id) { return Some(result); } - let canonical_ty = self.canonicalize(ty.clone().to_nextsolver(self.table.interner)); + let canonical_ty = self.canonicalize(ty); let mut not_visible = None; let res = method_resolution::iterate_method_candidates( @@ -362,24 +340,28 @@ impl<'db> InferenceContext<'db> { }; let substs = match container { ItemContainerId::ImplId(impl_id) => { - let interner = DbInterner::new_with(self.db, None, None); - let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None) - .fill_with_inference_vars(&mut self.table) - .build(); - let args: crate::next_solver::GenericArgs<'_> = impl_substs.to_nextsolver(interner); + let impl_substs = self.table.fresh_args_for_item(impl_id.into()); let impl_self_ty = - self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner); - self.unify(&impl_self_ty, &ty); + self.db.impl_self_ty(impl_id).instantiate(self.interner(), impl_substs); + self.unify(impl_self_ty, ty); impl_substs } ItemContainerId::TraitId(trait_) => { // we're picking this method - let trait_ref = TyBuilder::trait_ref(self.db, trait_) - .push(ty.clone()) - .fill_with_inference_vars(&mut self.table) - .build(); - self.push_obligation(trait_ref.clone().cast(Interner)); - trait_ref.substitution + let args = GenericArgs::fill_rest( + self.interner(), + trait_.into(), + [ty.into()], + |_, _, id, _| self.table.next_var_for_param(id), + ); + let trait_ref = TraitRef::new(self.interner(), trait_.into(), args); + self.table.register_predicate(Obligation::new( + self.interner(), + ObligationCause::new(), + self.table.trait_env.env, + trait_ref, + )); + args } ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => { never!("assoc item contained in module/extern block"); @@ -387,7 +369,7 @@ impl<'db> InferenceContext<'db> { } }; - self.write_assoc_resolution(id, item, substs.clone()); + self.write_assoc_resolution(id, item, substs); if !visible { self.push_diagnostic(InferenceDiagnostic::PrivateAssocItem { id, item }); } @@ -396,11 +378,11 @@ impl<'db> InferenceContext<'db> { fn resolve_enum_variant_on_ty( &mut self, - ty: &Ty, + ty: Ty<'db>, name: &Name, id: ExprOrPatId, - ) -> Option<(ValueNs, Substitution)> { - let ty = self.table.structurally_resolve_type(ty); + ) -> Option<(ValueNs, GenericArgs<'db>)> { + let ty = self.table.try_structurally_resolve_type(ty); let (enum_id, subst) = match ty.as_adt() { Some((AdtId::EnumId(e), subst)) => (e, subst), _ => return None, @@ -408,14 +390,14 @@ impl<'db> InferenceContext<'db> { let enum_data = enum_id.enum_variants(self.db); let variant = enum_data.variant(name)?; self.write_variant_resolution(id, variant.into()); - Some((ValueNs::EnumVariantId(variant), subst.clone())) + Some((ValueNs::EnumVariantId(variant), subst)) } } #[derive(Debug)] -enum ValuePathResolution { +enum ValuePathResolution<'db> { // It's awkward to wrap a single ID in two enums, but we need both and this saves fallible // conversion between them + `unwrap()`. - GenericDef(ValueTyDefId, GenericDefId, Substitution), - NonGeneric(Ty), + GenericDef(ValueTyDefId, GenericDefId, GenericArgs<'db>), + NonGeneric(Ty<'db>), } |