@@ -4,7 +4,7 @@ use chalk_ir::cast::Cast;
4
4
use hir_def:: {
5
5
path:: { Path , PathSegment } ,
6
6
resolver:: { ResolveValueResult , TypeNs , ValueNs } ,
7
- AdtId , AssocItemId , EnumVariantId , ItemContainerId , Lookup ,
7
+ AdtId , AssocItemId , EnumVariantId , GenericDefId , ItemContainerId , Lookup ,
8
8
} ;
9
9
use hir_expand:: name:: Name ;
10
10
use stdx:: never;
@@ -13,22 +13,33 @@ use crate::{
13
13
builder:: ParamKind ,
14
14
consteval,
15
15
method_resolution:: { self , VisibleFromModule } ,
16
+ to_chalk_trait_id,
16
17
utils:: generics,
17
18
InferenceDiagnostic , Interner , Substitution , TraitRefExt , Ty , TyBuilder , TyExt , TyKind ,
18
19
ValueTyDefId ,
19
20
} ;
20
21
21
22
use super :: { ExprOrPatId , InferenceContext , TraitRef } ;
22
23
23
- impl < ' a > InferenceContext < ' a > {
24
+ impl InferenceContext < ' _ > {
24
25
pub ( super ) fn infer_path ( & mut self , path : & Path , id : ExprOrPatId ) -> Option < Ty > {
25
- let ty = self . resolve_value_path ( path, id) ?;
26
- let ty = self . insert_type_vars ( ty) ;
26
+ let ( value_def, generic_def, substs) = match self . resolve_value_path ( path, id) ? {
27
+ ValuePathResolution :: GenericDef ( value_def, generic_def, substs) => {
28
+ ( value_def, generic_def, substs)
29
+ }
30
+ ValuePathResolution :: NonGeneric ( ty) => return Some ( ty) ,
31
+ } ;
32
+ let substs = self . insert_type_vars ( substs) ;
33
+ let substs = self . normalize_associated_types_in ( substs) ;
34
+
35
+ self . add_required_obligations_for_value_path ( generic_def, & substs) ;
36
+
37
+ let ty = self . db . value_ty ( value_def) . substitute ( Interner , & substs) ;
27
38
let ty = self . normalize_associated_types_in ( ty) ;
28
39
Some ( ty)
29
40
}
30
41
31
- fn resolve_value_path ( & mut self , path : & Path , id : ExprOrPatId ) -> Option < Ty > {
42
+ fn resolve_value_path ( & mut self , path : & Path , id : ExprOrPatId ) -> Option < ValuePathResolution > {
32
43
let ( value, self_subst) = if let Some ( type_ref) = path. type_anchor ( ) {
33
44
let last = path. segments ( ) . last ( ) ?;
34
45
@@ -56,9 +67,9 @@ impl<'a> InferenceContext<'a> {
56
67
}
57
68
} ;
58
69
59
- let typable : ValueTyDefId = match value {
70
+ let value_def = match value {
60
71
ValueNs :: LocalBinding ( pat) => match self . result . type_of_binding . get ( pat) {
61
- Some ( ty) => return Some ( ty. clone ( ) ) ,
72
+ Some ( ty) => return Some ( ValuePathResolution :: NonGeneric ( ty. clone ( ) ) ) ,
62
73
None => {
63
74
never ! ( "uninferred pattern?" ) ;
64
75
return None ;
@@ -82,36 +93,81 @@ impl<'a> InferenceContext<'a> {
82
93
let substs = generics. placeholder_subst ( self . db ) ;
83
94
let ty = self . db . impl_self_ty ( impl_id) . substitute ( Interner , & substs) ;
84
95
if let Some ( ( AdtId :: StructId ( struct_id) , substs) ) = ty. as_adt ( ) {
85
- let ty = self . db . value_ty ( struct_id. into ( ) ) . substitute ( Interner , & substs) ;
86
- return Some ( ty) ;
96
+ return Some ( ValuePathResolution :: GenericDef (
97
+ struct_id. into ( ) ,
98
+ struct_id. into ( ) ,
99
+ substs. clone ( ) ,
100
+ ) ) ;
87
101
} else {
88
102
// FIXME: report error, invalid Self reference
89
103
return None ;
90
104
}
91
105
}
92
- ValueNs :: GenericParam ( it) => return Some ( self . db . const_param_ty ( it) ) ,
106
+ ValueNs :: GenericParam ( it) => {
107
+ return Some ( ValuePathResolution :: NonGeneric ( self . db . const_param_ty ( it) ) )
108
+ }
93
109
} ;
94
110
95
111
let ctx = crate :: lower:: TyLoweringContext :: new ( self . db , & self . resolver ) ;
96
- let substs = ctx. substs_from_path ( path, typable , true ) ;
112
+ let substs = ctx. substs_from_path ( path, value_def , true ) ;
97
113
let substs = substs. as_slice ( Interner ) ;
98
114
let parent_substs = self_subst. or_else ( || {
99
- let generics = generics ( self . db . upcast ( ) , typable . to_generic_def_id ( ) ?) ;
115
+ let generics = generics ( self . db . upcast ( ) , value_def . to_generic_def_id ( ) ?) ;
100
116
let parent_params_len = generics. parent_generics ( ) ?. len ( ) ;
101
117
let parent_args = & substs[ substs. len ( ) - parent_params_len..] ;
102
118
Some ( Substitution :: from_iter ( Interner , parent_args) )
103
119
} ) ;
104
120
let parent_substs_len = parent_substs. as_ref ( ) . map_or ( 0 , |s| s. len ( Interner ) ) ;
105
121
let mut it = substs. iter ( ) . take ( substs. len ( ) - parent_substs_len) . cloned ( ) ;
106
- let ty = TyBuilder :: value_ty ( self . db , typable, parent_substs)
122
+
123
+ let Some ( generic_def) = value_def. to_generic_def_id ( ) else {
124
+ // `value_def` is the kind of item that can never be generic (i.e. statics, at least
125
+ // currently). We can just skip the binders to get its type.
126
+ let ( ty, binders) = self . db . value_ty ( value_def) . into_value_and_skipped_binders ( ) ;
127
+ stdx:: always!(
128
+ parent_substs. is_none( ) && binders. is_empty( Interner ) ,
129
+ "non-empty binders for non-generic def" ,
130
+ ) ;
131
+ return Some ( ValuePathResolution :: NonGeneric ( ty) ) ;
132
+ } ;
133
+ let builder = TyBuilder :: subst_for_def ( self . db , generic_def, parent_substs) ;
134
+ let substs = builder
107
135
. fill ( |x| {
108
136
it. next ( ) . unwrap_or_else ( || match x {
109
137
ParamKind :: Type => self . result . standard_types . unknown . clone ( ) . cast ( Interner ) ,
110
138
ParamKind :: Const ( ty) => consteval:: unknown_const_as_generic ( ty. clone ( ) ) ,
111
139
} )
112
140
} )
113
141
. build ( ) ;
114
- Some ( ty)
142
+
143
+ Some ( ValuePathResolution :: GenericDef ( value_def, generic_def, substs) )
144
+ }
145
+
146
+ fn add_required_obligations_for_value_path ( & mut self , def : GenericDefId , subst : & Substitution ) {
147
+ let predicates = self . db . generic_predicates ( def) ;
148
+ for predicate in predicates. iter ( ) {
149
+ let ( predicate, binders) =
150
+ predicate. clone ( ) . substitute ( Interner , & subst) . into_value_and_skipped_binders ( ) ;
151
+ // Quantified where clauses are not yet handled.
152
+ stdx:: always!( binders. is_empty( Interner ) ) ;
153
+ self . push_obligation ( predicate. cast ( Interner ) ) ;
154
+ }
155
+
156
+ // We need to add `Self: Trait` obligation when `def` is a trait assoc item.
157
+ let container = match def {
158
+ GenericDefId :: FunctionId ( id) => id. lookup ( self . db . upcast ( ) ) . container ,
159
+ GenericDefId :: ConstId ( id) => id. lookup ( self . db . upcast ( ) ) . container ,
160
+ _ => return ,
161
+ } ;
162
+
163
+ if let ItemContainerId :: TraitId ( trait_) = container {
164
+ let param_len = generics ( self . db . upcast ( ) , def) . len_self ( ) ;
165
+ let parent_subst =
166
+ Substitution :: from_iter ( Interner , subst. iter ( Interner ) . skip ( param_len) ) ;
167
+ let trait_ref =
168
+ TraitRef { trait_id : to_chalk_trait_id ( trait_) , substitution : parent_subst } ;
169
+ self . push_obligation ( trait_ref. cast ( Interner ) ) ;
170
+ }
115
171
}
116
172
117
173
fn resolve_assoc_item (
@@ -307,3 +363,10 @@ impl<'a> InferenceContext<'a> {
307
363
Some ( ( ValueNs :: EnumVariantId ( variant) , subst. clone ( ) ) )
308
364
}
309
365
}
366
+
367
+ enum ValuePathResolution {
368
+ // It's awkward to wrap a single ID in two enums, but we need both and this saves fallible
369
+ // conversion between them + `unwrap()`.
370
+ GenericDef ( ValueTyDefId , GenericDefId , Substitution ) ,
371
+ NonGeneric ( Ty ) ,
372
+ }
0 commit comments