aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-25 11:25:53 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-25 11:25:53 +0000
commit04ce89313369a1606b057b3be1368d72b8a5cd63 (patch)
treed85e49c985b92a9ccf1303a089dccdd4c805db1c
parentae97cd59ff086e7efb6409f14c2f8ae8861596e4 (diff)
parent64d4f4255880bbfb400551db38b76871276eaca6 (diff)
Merge #638
638: reduce visibility r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--crates/ra_arena/src/lib.rs13
-rw-r--r--crates/ra_hir/src/adt.rs100
-rw-r--r--crates/ra_hir/src/code_model_api.rs65
-rw-r--r--crates/ra_hir/src/db.rs8
-rw-r--r--crates/ra_hir/src/ty.rs90
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs4
6 files changed, 143 insertions, 137 deletions
diff --git a/crates/ra_arena/src/lib.rs b/crates/ra_arena/src/lib.rs
index d7d5d5265..97f554838 100644
--- a/crates/ra_arena/src/lib.rs
+++ b/crates/ra_arena/src/lib.rs
@@ -4,6 +4,7 @@ use std::{
4 fmt, 4 fmt,
5 marker::PhantomData, 5 marker::PhantomData,
6 ops::{Index, IndexMut}, 6 ops::{Index, IndexMut},
7 iter::FromIterator,
7}; 8};
8 9
9pub mod map; 10pub mod map;
@@ -109,3 +110,15 @@ impl<ID: ArenaId, T> IndexMut<ID> for Arena<ID, T> {
109 &mut self.data[idx] 110 &mut self.data[idx]
110 } 111 }
111} 112}
113
114impl<ID: ArenaId, T> FromIterator<T> for Arena<ID, T> {
115 fn from_iter<I>(iter: I) -> Self
116 where
117 I: IntoIterator<Item = T>,
118 {
119 Arena {
120 data: Vec::from_iter(iter),
121 _ty: PhantomData,
122 }
123 }
124}
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index dc936e826..ec6a10353 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -79,12 +79,13 @@ impl EnumVariant {
79 .to_owned(); 79 .to_owned();
80 (file_id, var) 80 (file_id, var)
81 } 81 }
82 pub(crate) fn variant_data(&self, db: &impl HirDatabase) -> Arc<VariantData> {
83 db.enum_data(self.parent).variants[self.id]
84 .variant_data
85 .clone()
86 }
82} 87}
83 88
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
85pub(crate) struct EnumVariantId(RawId);
86impl_arena_id!(EnumVariantId);
87
88#[derive(Debug, Clone, PartialEq, Eq)] 89#[derive(Debug, Clone, PartialEq, Eq)]
89pub struct EnumData { 90pub struct EnumData {
90 pub(crate) name: Option<Name>, 91 pub(crate) name: Option<Name>,
@@ -94,105 +95,84 @@ pub struct EnumData {
94impl EnumData { 95impl EnumData {
95 pub(crate) fn enum_data_query(db: &impl HirDatabase, e: Enum) -> Arc<EnumData> { 96 pub(crate) fn enum_data_query(db: &impl HirDatabase, e: Enum) -> Arc<EnumData> {
96 let (_file_id, enum_def) = e.source(db); 97 let (_file_id, enum_def) = e.source(db);
97 let mut res = EnumData { 98 let name = enum_def.name().map(|n| n.as_name());
98 name: enum_def.name().map(|n| n.as_name()), 99 let variants = variants(&*enum_def)
99 variants: Arena::default(), 100 .map(|var| EnumVariantData {
100 };
101 for var in variants(&*enum_def) {
102 let data = EnumVariantData {
103 name: var.name().map(|it| it.as_name()), 101 name: var.name().map(|it| it.as_name()),
104 variant_data: Arc::new(VariantData::new(var.flavor())), 102 variant_data: Arc::new(VariantData::new(var.flavor())),
105 }; 103 })
106 res.variants.alloc(data); 104 .collect();
107 } 105 Arc::new(EnumData { name, variants })
108
109 Arc::new(res)
110 } 106 }
111} 107}
112 108
109#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
110pub(crate) struct EnumVariantId(RawId);
111impl_arena_id!(EnumVariantId);
112
113#[derive(Debug, Clone, PartialEq, Eq)] 113#[derive(Debug, Clone, PartialEq, Eq)]
114pub struct EnumVariantData { 114pub(crate) struct EnumVariantData {
115 pub(crate) name: Option<Name>, 115 pub(crate) name: Option<Name>,
116 pub(crate) variant_data: Arc<VariantData>, 116 variant_data: Arc<VariantData>,
117} 117}
118 118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
120pub(crate) struct StructFieldId(RawId);
121impl_arena_id!(StructFieldId);
122
119/// A single field of an enum variant or struct 123/// A single field of an enum variant or struct
120#[derive(Debug, Clone, PartialEq, Eq)] 124#[derive(Debug, Clone, PartialEq, Eq)]
121pub struct StructField { 125pub struct StructFieldData {
122 pub(crate) name: Name, 126 pub(crate) name: Name,
123 pub(crate) type_ref: TypeRef, 127 pub(crate) type_ref: TypeRef,
124} 128}
125 129
126/// Fields of an enum variant or struct 130/// Fields of an enum variant or struct
127#[derive(Debug, Clone, PartialEq, Eq)] 131#[derive(Debug, Clone, PartialEq, Eq)]
128pub enum VariantData { 132pub(crate) struct VariantData(VariantDataInner);
129 Struct(Vec<StructField>), 133
130 Tuple(Vec<StructField>), 134#[derive(Debug, Clone, PartialEq, Eq)]
135enum VariantDataInner {
136 Struct(Arena<StructFieldId, StructFieldData>),
137 Tuple(Arena<StructFieldId, StructFieldData>),
131 Unit, 138 Unit,
132} 139}
133 140
134impl VariantData { 141impl VariantData {
135 pub fn fields(&self) -> &[StructField] { 142 pub(crate) fn fields(&self) -> Option<&Arena<StructFieldId, StructFieldData>> {
136 match self { 143 match &self.0 {
137 VariantData::Struct(fields) | VariantData::Tuple(fields) => fields, 144 VariantDataInner::Struct(fields) | VariantDataInner::Tuple(fields) => Some(fields),
138 _ => &[], 145 _ => None,
139 }
140 }
141
142 pub fn is_struct(&self) -> bool {
143 match self {
144 VariantData::Struct(..) => true,
145 _ => false,
146 }
147 }
148
149 pub fn is_tuple(&self) -> bool {
150 match self {
151 VariantData::Tuple(..) => true,
152 _ => false,
153 }
154 }
155
156 pub fn is_unit(&self) -> bool {
157 match self {
158 VariantData::Unit => true,
159 _ => false,
160 } 146 }
161 } 147 }
162} 148}
163 149
164impl VariantData { 150impl VariantData {
165 fn new(flavor: StructFlavor) -> Self { 151 fn new(flavor: StructFlavor) -> Self {
166 match flavor { 152 let inner = match flavor {
167 StructFlavor::Tuple(fl) => { 153 StructFlavor::Tuple(fl) => {
168 let fields = fl 154 let fields = fl
169 .fields() 155 .fields()
170 .enumerate() 156 .enumerate()
171 .map(|(i, fd)| StructField { 157 .map(|(i, fd)| StructFieldData {
172 name: Name::tuple_field_name(i), 158 name: Name::tuple_field_name(i),
173 type_ref: TypeRef::from_ast_opt(fd.type_ref()), 159 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
174 }) 160 })
175 .collect(); 161 .collect();
176 VariantData::Tuple(fields) 162 VariantDataInner::Tuple(fields)
177 } 163 }
178 StructFlavor::Named(fl) => { 164 StructFlavor::Named(fl) => {
179 let fields = fl 165 let fields = fl
180 .fields() 166 .fields()
181 .map(|fd| StructField { 167 .map(|fd| StructFieldData {
182 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), 168 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
183 type_ref: TypeRef::from_ast_opt(fd.type_ref()), 169 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
184 }) 170 })
185 .collect(); 171 .collect();
186 VariantData::Struct(fields) 172 VariantDataInner::Struct(fields)
187 } 173 }
188 StructFlavor::Unit => VariantData::Unit, 174 StructFlavor::Unit => VariantDataInner::Unit,
189 } 175 };
190 } 176 VariantData(inner)
191
192 pub(crate) fn get_field_type_ref(&self, field_name: &Name) -> Option<&TypeRef> {
193 self.fields()
194 .iter()
195 .find(|f| f.name == *field_name)
196 .map(|f| &f.type_ref)
197 } 177 }
198} 178}
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 249a4aba9..118562984 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -11,7 +11,7 @@ use crate::{
11 db::HirDatabase, 11 db::HirDatabase,
12 expr::BodySyntaxMapping, 12 expr::BodySyntaxMapping,
13 ty::{InferenceResult, VariantDef}, 13 ty::{InferenceResult, VariantDef},
14 adt::{VariantData, EnumVariantId}, 14 adt::{EnumVariantId, StructFieldId},
15 generics::GenericParams, 15 generics::GenericParams,
16 docs::{Documentation, Docs, docs_from_ast}, 16 docs::{Documentation, Docs, docs_from_ast},
17 module_tree::ModuleId, 17 module_tree::ModuleId,
@@ -177,19 +177,25 @@ impl Module {
177 } 177 }
178} 178}
179 179
180#[derive(Debug, Clone, PartialEq, Eq, Hash)] 180#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
181pub struct StructField { 181pub struct StructField {
182 parent: VariantDef, 182 parent: VariantDef,
183 name: Name, 183 pub(crate) id: StructFieldId,
184} 184}
185 185
186impl StructField { 186impl StructField {
187 pub fn name(&self) -> &Name { 187 pub fn name(&self, db: &impl HirDatabase) -> Name {
188 &self.name 188 self.parent.variant_data(db).fields().unwrap()[self.id]
189 .name
190 .clone()
189 } 191 }
190 192
191 pub fn ty(&self, db: &impl HirDatabase) -> Option<Ty> { 193 pub fn ty(&self, db: &impl HirDatabase) -> Ty {
192 db.type_for_field(self.parent, self.name.clone()) 194 db.type_for_field(*self)
195 }
196
197 pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef {
198 self.parent
193 } 199 }
194} 200}
195 201
@@ -215,14 +221,28 @@ impl Struct {
215 db.struct_data(*self) 221 db.struct_data(*self)
216 .variant_data 222 .variant_data
217 .fields() 223 .fields()
218 .iter() 224 .into_iter()
219 .map(|it| StructField { 225 .flat_map(|it| it.iter())
226 .map(|(id, _)| StructField {
220 parent: (*self).into(), 227 parent: (*self).into(),
221 name: it.name.clone(), 228 id,
222 }) 229 })
223 .collect() 230 .collect()
224 } 231 }
225 232
233 pub fn field(&self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
234 db.struct_data(*self)
235 .variant_data
236 .fields()
237 .into_iter()
238 .flat_map(|it| it.iter())
239 .find(|(_id, data)| data.name == *name)
240 .map(|(id, _)| StructField {
241 parent: (*self).into(),
242 id,
243 })
244 }
245
226 pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { 246 pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> {
227 db.generic_params((*self).into()) 247 db.generic_params((*self).into())
228 } 248 }
@@ -300,22 +320,29 @@ impl EnumVariant {
300 db.enum_data(self.parent).variants[self.id].name.clone() 320 db.enum_data(self.parent).variants[self.id].name.clone()
301 } 321 }
302 322
303 pub fn variant_data(&self, db: &impl HirDatabase) -> Arc<VariantData> {
304 db.enum_data(self.parent).variants[self.id]
305 .variant_data
306 .clone()
307 }
308
309 pub fn fields(&self, db: &impl HirDatabase) -> Vec<StructField> { 323 pub fn fields(&self, db: &impl HirDatabase) -> Vec<StructField> {
310 self.variant_data(db) 324 self.variant_data(db)
311 .fields() 325 .fields()
312 .iter() 326 .into_iter()
313 .map(|it| StructField { 327 .flat_map(|it| it.iter())
328 .map(|(id, _)| StructField {
314 parent: (*self).into(), 329 parent: (*self).into(),
315 name: it.name.clone(), 330 id,
316 }) 331 })
317 .collect() 332 .collect()
318 } 333 }
334
335 pub fn field(&self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
336 self.variant_data(db)
337 .fields()
338 .into_iter()
339 .flat_map(|it| it.iter())
340 .find(|(_id, data)| data.name == *name)
341 .map(|(id, _)| StructField {
342 parent: (*self).into(),
343 id,
344 })
345 }
319} 346}
320 347
321impl Docs for EnumVariant { 348impl Docs for EnumVariant {
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 5a29e54d6..3c82262a2 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -4,15 +4,15 @@ use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
4use ra_db::{SyntaxDatabase, CrateId, salsa}; 4use ra_db::{SyntaxDatabase, CrateId, salsa};
5 5
6use crate::{ 6use crate::{
7 MacroCallId, Name, HirFileId, 7 MacroCallId, HirFileId,
8 SourceFileItems, SourceItemId, Crate, Module, HirInterner, 8 SourceFileItems, SourceItemId, Crate, Module, HirInterner,
9 query_definitions, 9 query_definitions,
10 Function, FnSignature, FnScopes, 10 Function, FnSignature, FnScopes,
11 Struct, Enum, 11 Struct, Enum, StructField,
12 macros::MacroExpansion, 12 macros::MacroExpansion,
13 module_tree::ModuleTree, 13 module_tree::ModuleTree,
14 nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}}, 14 nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
15 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, VariantDef}, 15 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef},
16 adt::{StructData, EnumData}, 16 adt::{StructData, EnumData},
17 impl_block::ModuleImplBlocks, 17 impl_block::ModuleImplBlocks,
18 generics::{GenericParams, GenericDef}, 18 generics::{GenericParams, GenericDef},
@@ -42,7 +42,7 @@ pub trait HirDatabase: SyntaxDatabase + AsRef<HirInterner> {
42 fn type_for_def(&self, def: TypableDef) -> Ty; 42 fn type_for_def(&self, def: TypableDef) -> Ty;
43 43
44 #[salsa::invoke(crate::ty::type_for_field)] 44 #[salsa::invoke(crate::ty::type_for_field)]
45 fn type_for_field(&self, def: VariantDef, field: Name) -> Option<Ty>; 45 fn type_for_field(&self, field: StructField) -> Ty;
46 46
47 #[salsa::invoke(query_definitions::file_items)] 47 #[salsa::invoke(query_definitions::file_items)]
48 fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>; 48 fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>;
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index c7f77e7a3..c57e222dd 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -38,6 +38,7 @@ use crate::{
38 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat}, 38 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat},
39 generics::GenericParams, 39 generics::GenericParams,
40 path::GenericArg, 40 path::GenericArg,
41 adt::VariantData,
41}; 42};
42 43
43/// The ID of a type variable. 44/// The ID of a type variable.
@@ -702,19 +703,30 @@ pub enum VariantDef {
702} 703}
703impl_froms!(VariantDef: Struct, EnumVariant); 704impl_froms!(VariantDef: Struct, EnumVariant);
704 705
705pub(super) fn type_for_field(db: &impl HirDatabase, def: VariantDef, field: Name) -> Option<Ty> { 706impl VariantDef {
706 let (variant_data, generics, module) = match def { 707 pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
707 VariantDef::Struct(s) => (s.variant_data(db), s.generic_params(db), s.module(db)), 708 match self {
708 VariantDef::EnumVariant(var) => ( 709 VariantDef::Struct(it) => it.field(db, name),
709 var.variant_data(db), 710 VariantDef::EnumVariant(it) => it.field(db, name),
710 var.parent_enum(db).generic_params(db), 711 }
711 var.module(db), 712 }
712 ), 713 pub(crate) fn variant_data(self, db: &impl HirDatabase) -> Arc<VariantData> {
714 match self {
715 VariantDef::Struct(it) => it.variant_data(db),
716 VariantDef::EnumVariant(it) => it.variant_data(db),
717 }
718 }
719}
720
721pub(super) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
722 let parent_def = field.parent_def(db);
723 let (generics, module) = match parent_def {
724 VariantDef::Struct(it) => (it.generic_params(db), it.module(db)),
725 VariantDef::EnumVariant(it) => (it.parent_enum(db).generic_params(db), it.module(db)),
713 }; 726 };
714 // We can't have an impl block ere, right? 727 let var_data = parent_def.variant_data(db);
715 // let impl_block = def_id.impl_block(db); 728 let type_ref = &var_data.fields().unwrap()[field.id].type_ref;
716 let type_ref = variant_data.get_field_type_ref(&field)?; 729 Ty::from_hir(db, &module, None, &generics, type_ref)
717 Some(Ty::from_hir(db, &module, None, &generics, &type_ref))
718} 730}
719 731
720/// The result of type inference: A mapping from expressions and patterns to types. 732/// The result of type inference: A mapping from expressions and patterns to types.
@@ -1122,39 +1134,22 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1122 } 1134 }
1123 } 1135 }
1124 1136
1125 fn resolve_fields(&mut self, path: Option<&Path>) -> Option<(Ty, Vec<StructField>)> {
1126 let (ty, def) = self.resolve_variant(path);
1127 match def? {
1128 VariantDef::Struct(s) => {
1129 let fields = s.fields(self.db);
1130 Some((ty, fields))
1131 }
1132 VariantDef::EnumVariant(var) => {
1133 let fields = var.fields(self.db);
1134 Some((ty, fields))
1135 }
1136 }
1137 }
1138
1139 fn infer_tuple_struct_pat( 1137 fn infer_tuple_struct_pat(
1140 &mut self, 1138 &mut self,
1141 path: Option<&Path>, 1139 path: Option<&Path>,
1142 subpats: &[PatId], 1140 subpats: &[PatId],
1143 expected: &Ty, 1141 expected: &Ty,
1144 ) -> Ty { 1142 ) -> Ty {
1145 let (ty, fields) = self 1143 let (ty, def) = self.resolve_variant(path);
1146 .resolve_fields(path)
1147 .unwrap_or((Ty::Unknown, Vec::new()));
1148 1144
1149 self.unify(&ty, expected); 1145 self.unify(&ty, expected);
1150 1146
1151 let substs = ty.substs().unwrap_or_else(Substs::empty); 1147 let substs = ty.substs().unwrap_or_else(Substs::empty);
1152 1148
1153 for (i, &subpat) in subpats.iter().enumerate() { 1149 for (i, &subpat) in subpats.iter().enumerate() {
1154 let expected_ty = fields 1150 let expected_ty = def
1155 .get(i) 1151 .and_then(|d| d.field(self.db, &Name::tuple_field_name(i)))
1156 .and_then(|field| field.ty(self.db)) 1152 .map_or(Ty::Unknown, |field| field.ty(self.db))
1157 .unwrap_or(Ty::Unknown)
1158 .subst(&substs); 1153 .subst(&substs);
1159 self.infer_pat(subpat, &expected_ty); 1154 self.infer_pat(subpat, &expected_ty);
1160 } 1155 }
@@ -1163,19 +1158,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1163 } 1158 }
1164 1159
1165 fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty { 1160 fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty {
1166 let (ty, fields) = self 1161 let (ty, def) = self.resolve_variant(path);
1167 .resolve_fields(path)
1168 .unwrap_or((Ty::Unknown, Vec::new()));
1169 1162
1170 self.unify(&ty, expected); 1163 self.unify(&ty, expected);
1171 1164
1172 let substs = ty.substs().unwrap_or_else(Substs::empty); 1165 let substs = ty.substs().unwrap_or_else(Substs::empty);
1173 1166
1174 for subpat in subpats { 1167 for subpat in subpats {
1175 let matching_field = fields.iter().find(|field| field.name() == &subpat.name); 1168 let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
1176 let expected_ty = matching_field 1169 let expected_ty = matching_field
1177 .and_then(|field| field.ty(self.db)) 1170 .map_or(Ty::Unknown, |field| field.ty(self.db))
1178 .unwrap_or(Ty::Unknown)
1179 .subst(&substs); 1171 .subst(&substs);
1180 self.infer_pat(subpat.pat, &expected_ty); 1172 self.infer_pat(subpat.pat, &expected_ty);
1181 } 1173 }
@@ -1420,14 +1412,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1420 let (ty, def_id) = self.resolve_variant(path.as_ref()); 1412 let (ty, def_id) = self.resolve_variant(path.as_ref());
1421 let substs = ty.substs().unwrap_or_else(Substs::empty); 1413 let substs = ty.substs().unwrap_or_else(Substs::empty);
1422 for field in fields { 1414 for field in fields {
1423 let field_ty = if let Some(def_id) = def_id { 1415 let field_ty = def_id
1424 self.db 1416 .and_then(|it| it.field(self.db, &field.name))
1425 .type_for_field(def_id.into(), field.name.clone()) 1417 .map_or(Ty::Unknown, |field| field.ty(self.db))
1426 .unwrap_or(Ty::Unknown) 1418 .subst(&substs);
1427 .subst(&substs)
1428 } else {
1429 Ty::Unknown
1430 };
1431 self.infer_expr(field.expr, &Expectation::has_type(field_ty)); 1419 self.infer_expr(field.expr, &Expectation::has_type(field_ty));
1432 } 1420 }
1433 if let Some(expr) = spread { 1421 if let Some(expr) = spread {
@@ -1440,7 +1428,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1440 let ty = receiver_ty 1428 let ty = receiver_ty
1441 .autoderef(self.db) 1429 .autoderef(self.db)
1442 .find_map(|derefed_ty| match derefed_ty { 1430 .find_map(|derefed_ty| match derefed_ty {
1443 // this is more complicated than necessary because type_for_field is cancelable
1444 Ty::Tuple(fields) => { 1431 Ty::Tuple(fields) => {
1445 let i = name.to_string().parse::<usize>().ok(); 1432 let i = name.to_string().parse::<usize>().ok();
1446 i.and_then(|i| fields.get(i).cloned()) 1433 i.and_then(|i| fields.get(i).cloned())
@@ -1449,10 +1436,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1449 def_id: AdtDef::Struct(s), 1436 def_id: AdtDef::Struct(s),
1450 ref substs, 1437 ref substs,
1451 .. 1438 ..
1452 } => self 1439 } => s
1453 .db 1440 .field(self.db, name)
1454 .type_for_field(s.into(), name.clone()) 1441 .map(|field| field.ty(self.db).subst(substs)),
1455 .map(|ty| ty.subst(substs)),
1456 _ => None, 1442 _ => None,
1457 }) 1443 })
1458 .unwrap_or(Ty::Unknown); 1444 .unwrap_or(Ty::Unknown);
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index 6a9358d33..060a46c5e 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -34,10 +34,10 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
34 CompletionItem::new( 34 CompletionItem::new(
35 CompletionKind::Reference, 35 CompletionKind::Reference,
36 ctx.source_range(), 36 ctx.source_range(),
37 field.name().to_string(), 37 field.name(ctx.db).to_string(),
38 ) 38 )
39 .kind(CompletionItemKind::Field) 39 .kind(CompletionItemKind::Field)
40 .set_detail(field.ty(ctx.db).map(|ty| ty.subst(substs).to_string())) 40 .detail(field.ty(ctx.db).subst(substs).to_string())
41 .add_to(acc); 41 .add_to(acc);
42 } 42 }
43 } 43 }