1 //! Path expression resolution.
3 use chalk_ir
::cast
::Cast
;
5 path
::{Path, PathSegment}
,
6 resolver
::{ResolveValueResult, Resolver, TypeNs, ValueNs}
,
7 AdtId
, AssocItemId
, EnumVariantId
, ItemContainerId
, Lookup
,
9 use hir_expand
::name
::Name
;
15 method_resolution
::{self, VisibleFromModule}
,
17 InferenceDiagnostic
, Interner
, Substitution
, TraitRefExt
, Ty
, TyBuilder
, TyExt
, TyKind
,
21 use super::{ExprOrPatId, InferenceContext, TraitRef}
;
23 impl<'a
> InferenceContext
<'a
> {
24 pub(super) fn infer_path(
30 let ty
= self.resolve_value_path(resolver
, path
, id
)?
;
31 let ty
= self.insert_type_vars(ty
);
32 let ty
= self.normalize_associated_types_in(ty
);
36 fn resolve_value_path(
42 let (value
, self_subst
) = if let Some(type_ref
) = path
.type_anchor() {
43 if path
.segments().is_empty() {
44 // This can't actually happen syntax-wise
47 let ty
= self.make_ty(type_ref
);
48 let remaining_segments_for_ty
= path
.segments().take(path
.segments().len() - 1);
49 let ctx
= crate::lower
::TyLoweringContext
::new(self.db
, resolver
);
50 let (ty
, _
) = ctx
.lower_ty_relative_path(ty
, None
, remaining_segments_for_ty
);
51 self.resolve_ty_assoc_item(
53 path
.segments().last().expect("path had at least one segment").name
,
57 let value_or_partial
=
58 resolver
.resolve_path_in_value_ns(self.db
.upcast(), path
.mod_path())?
;
60 match value_or_partial
{
61 ResolveValueResult
::ValueNs(it
) => (it
, None
),
62 ResolveValueResult
::Partial(def
, remaining_index
) => {
63 self.resolve_assoc_item(def
, path
, remaining_index
, id
)?
68 let typable
: ValueTyDefId
= match value
{
69 ValueNs
::LocalBinding(pat
) => {
70 let ty
= self.result
.type_of_pat
.get(pat
)?
.clone();
73 ValueNs
::FunctionId(it
) => it
.into(),
74 ValueNs
::ConstId(it
) => it
.into(),
75 ValueNs
::StaticId(it
) => it
.into(),
76 ValueNs
::StructId(it
) => {
77 self.write_variant_resolution(id
, it
.into());
81 ValueNs
::EnumVariantId(it
) => {
82 self.write_variant_resolution(id
, it
.into());
86 ValueNs
::ImplSelf(impl_id
) => {
87 let generics
= crate::utils
::generics(self.db
.upcast(), impl_id
.into());
88 let substs
= generics
.placeholder_subst(self.db
);
89 let ty
= self.db
.impl_self_ty(impl_id
).substitute(Interner
, &substs
);
90 if let Some((AdtId
::StructId(struct_id
), substs
)) = ty
.as_adt() {
91 let ty
= self.db
.value_ty(struct_id
.into()).substitute(Interner
, &substs
);
94 // FIXME: diagnostic, invalid Self reference
98 ValueNs
::GenericParam(it
) => return Some(self.db
.const_param_ty(it
)),
101 let ctx
= crate::lower
::TyLoweringContext
::new(self.db
, &self.resolver
);
102 let substs
= ctx
.substs_from_path(path
, typable
, true);
103 let substs
= substs
.as_slice(Interner
);
104 let parent_substs
= self_subst
.or_else(|| {
105 let generics
= generics(self.db
.upcast(), typable
.to_generic_def_id()?
);
106 let parent_params_len
= generics
.parent_generics()?
.len();
107 let parent_args
= &substs
[substs
.len() - parent_params_len
..];
108 Some(Substitution
::from_iter(Interner
, parent_args
))
110 let parent_substs_len
= parent_substs
.as_ref().map_or(0, |s
| s
.len(Interner
));
111 let mut it
= substs
.iter().take(substs
.len() - parent_substs_len
).cloned();
112 let ty
= TyBuilder
::value_ty(self.db
, typable
, parent_substs
)
114 it
.next().unwrap_or_else(|| match x
{
115 ParamKind
::Type
=> TyKind
::Error
.intern(Interner
).cast(Interner
),
116 ParamKind
::Const(ty
) => consteval
::unknown_const_as_generic(ty
.clone()),
123 fn resolve_assoc_item(
127 remaining_index
: usize,
129 ) -> Option
<(ValueNs
, Option
<Substitution
>)> {
130 assert
!(remaining_index
< path
.segments().len());
131 // there may be more intermediate segments between the resolved one and
132 // the end. Only the last segment needs to be resolved to a value; from
133 // the segments before that, we need to get either a type or a trait ref.
135 let resolved_segment
= path
.segments().get(remaining_index
- 1).unwrap();
136 let remaining_segments
= path
.segments().skip(remaining_index
);
137 let is_before_last
= remaining_segments
.len() == 1;
139 match (def
, is_before_last
) {
140 (TypeNs
::TraitId(trait_
), true) => {
142 remaining_segments
.last().expect("there should be at least one segment here");
143 let ctx
= crate::lower
::TyLoweringContext
::new(self.db
, &self.resolver
);
145 ctx
.lower_trait_ref_from_resolved_path(trait_
, resolved_segment
, None
);
146 self.resolve_trait_assoc_item(trait_ref
, segment
, id
)
149 // Either we already have a type (e.g. `Vec::new`), or we have a
150 // trait but it's not the last segment, so the next segment
151 // should resolve to an associated type of that trait (e.g. `<T
152 // as Iterator>::Item::default`)
153 let remaining_segments_for_ty
=
154 remaining_segments
.take(remaining_segments
.len() - 1);
155 let ctx
= crate::lower
::TyLoweringContext
::new(self.db
, &self.resolver
);
156 let (ty
, _
) = ctx
.lower_partly_resolved_path(
159 remaining_segments_for_ty
,
166 let ty
= self.insert_type_vars(ty
);
167 let ty
= self.normalize_associated_types_in(ty
);
170 remaining_segments
.last().expect("there should be at least one segment here");
172 self.resolve_ty_assoc_item(ty
, segment
.name
, id
)
177 fn resolve_trait_assoc_item(
180 segment
: PathSegment
<'_
>,
182 ) -> Option
<(ValueNs
, Option
<Substitution
>)> {
183 let trait_
= trait_ref
.hir_trait_id();
185 self.db
.trait_data(trait_
).items
.iter().map(|(_name
, id
)| (*id
)).find_map(|item
| {
187 AssocItemId
::FunctionId(func
) => {
188 if segment
.name
== &self.db
.function_data(func
).name
{
189 Some(AssocItemId
::FunctionId(func
))
195 AssocItemId
::ConstId(konst
) => {
201 .map_or(false, |n
| n
== segment
.name
)
203 Some(AssocItemId
::ConstId(konst
))
208 AssocItemId
::TypeAliasId(_
) => None
,
211 let def
= match item
{
212 AssocItemId
::FunctionId(f
) => ValueNs
::FunctionId(f
),
213 AssocItemId
::ConstId(c
) => ValueNs
::ConstId(c
),
214 AssocItemId
::TypeAliasId(_
) => unreachable
!(),
217 self.write_assoc_resolution(id
, item
, trait_ref
.substitution
.clone());
218 Some((def
, Some(trait_ref
.substitution
)))
221 fn resolve_ty_assoc_item(
226 ) -> Option
<(ValueNs
, Option
<Substitution
>)> {
227 if let TyKind
::Error
= ty
.kind(Interner
) {
231 if let Some(result
) = self.resolve_enum_variant_on_ty(&ty
, name
, id
) {
235 let canonical_ty
= self.canonicalize(ty
.clone());
236 let traits_in_scope
= self.resolver
.traits_in_scope(self.db
.upcast());
238 let mut not_visible
= None
;
239 let res
= method_resolution
::iterate_method_candidates(
242 self.table
.trait_env
.clone(),
244 VisibleFromModule
::Filter(self.resolver
.module()),
246 method_resolution
::LookupMode
::Path
,
247 |_ty
, item
, visible
| {
248 let (def
, container
) = match item
{
249 AssocItemId
::FunctionId(f
) => {
250 (ValueNs
::FunctionId(f
), f
.lookup(self.db
.upcast()).container
)
252 AssocItemId
::ConstId(c
) => {
253 (ValueNs
::ConstId(c
), c
.lookup(self.db
.upcast()).container
)
255 AssocItemId
::TypeAliasId(_
) => unreachable
!(),
257 let substs
= match container
{
258 ItemContainerId
::ImplId(impl_id
) => {
259 let impl_substs
= TyBuilder
::subst_for_def(self.db
, impl_id
, None
)
260 .fill_with_inference_vars(&mut self.table
)
263 self.db
.impl_self_ty(impl_id
).substitute(Interner
, &impl_substs
);
264 self.unify(&impl_self_ty
, &ty
);
267 ItemContainerId
::TraitId(trait_
) => {
268 // we're picking this method
269 let trait_ref
= TyBuilder
::trait_ref(self.db
, trait_
)
271 .fill_with_inference_vars(&mut self.table
)
273 self.push_obligation(trait_ref
.clone().cast(Interner
));
274 trait_ref
.substitution
276 ItemContainerId
::ModuleId(_
) | ItemContainerId
::ExternBlockId(_
) => {
277 never
!("assoc item contained in module/extern block");
283 Some((def
, item
, Some(substs
), true))
285 if not_visible
.is_none() {
286 not_visible
= Some((def
, item
, Some(substs
), false));
292 let res
= res
.or(not_visible
);
293 if let Some((_
, item
, Some(ref substs
), visible
)) = res
{
294 self.write_assoc_resolution(id
, item
, substs
.clone());
296 self.push_diagnostic(InferenceDiagnostic
::PrivateAssocItem { id, item }
)
299 res
.map(|(def
, _
, substs
, _
)| (def
, substs
))
302 fn resolve_enum_variant_on_ty(
307 ) -> Option
<(ValueNs
, Option
<Substitution
>)> {
308 let ty
= self.resolve_ty_shallow(ty
);
309 let (enum_id
, subst
) = match ty
.as_adt() {
310 Some((AdtId
::EnumId(e
), subst
)) => (e
, subst
),
313 let enum_data
= self.db
.enum_data(enum_id
);
314 let local_id
= enum_data
.variant(name
)?
;
315 let variant
= EnumVariantId { parent: enum_id, local_id }
;
316 self.write_variant_resolution(id
, variant
.into());
317 Some((ValueNs
::EnumVariantId(variant
), Some(subst
.clone())))