diff options
author | Florian Diebold <[email protected]> | 2019-05-05 13:42:12 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-05-11 15:21:20 +0100 |
commit | 58b68966bf0e0d5ae5c56e2da1d6def5e0ec0925 (patch) | |
tree | 2d92dbadd7f6cbf756766040eec8685688415241 /crates/ra_hir/src/ty | |
parent | 50bbf9eb09dc34781cc34e10bfba5f154e833123 (diff) |
Handle resolution errors in where clauses
This is slightly hacky, but maybe more elegant than alternative solutions: We
just use a hardcoded Chalk trait ID which we special-case to have no impls.
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 56 |
2 files changed, 56 insertions, 15 deletions
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index c3edf42b1..3c55a093f 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2502,6 +2502,21 @@ fn test() { (&S).foo()<|>; } | |||
2502 | } | 2502 | } |
2503 | 2503 | ||
2504 | #[test] | 2504 | #[test] |
2505 | fn method_resolution_where_clause_for_unknown_trait() { | ||
2506 | // The blanket impl shouldn't apply because we can't even resolve UnknownTrait | ||
2507 | let t = type_at( | ||
2508 | r#" | ||
2509 | //- /main.rs | ||
2510 | trait Trait { fn foo(self) -> u128; } | ||
2511 | struct S; | ||
2512 | impl<T> Trait for T where T: UnknownTrait {} | ||
2513 | fn test() { (&S).foo()<|>; } | ||
2514 | "#, | ||
2515 | ); | ||
2516 | assert_eq!(t, "{unknown}"); | ||
2517 | } | ||
2518 | |||
2519 | #[test] | ||
2505 | fn method_resolution_where_clause_not_met() { | 2520 | fn method_resolution_where_clause_not_met() { |
2506 | // The blanket impl shouldn't apply because we can't prove S: Clone | 2521 | // The blanket impl shouldn't apply because we can't prove S: Clone |
2507 | let t = type_at( | 2522 | let t = type_at( |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 2772a0432..787970186 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -15,6 +15,10 @@ use crate::{ | |||
15 | }; | 15 | }; |
16 | use super::ChalkContext; | 16 | use super::ChalkContext; |
17 | 17 | ||
18 | /// This represents a trait whose name we could not resolve. | ||
19 | const UNKNOWN_TRAIT: chalk_ir::TraitId = | ||
20 | chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() }); | ||
21 | |||
18 | pub(super) trait ToChalk { | 22 | pub(super) trait ToChalk { |
19 | type Chalk; | 23 | type Chalk; |
20 | fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk; | 24 | fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk; |
@@ -45,7 +49,10 @@ impl ToChalk for Ty { | |||
45 | Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), | 49 | Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), |
46 | // FIXME this is clearly incorrect, but probably not too incorrect | 50 | // FIXME this is clearly incorrect, but probably not too incorrect |
47 | // and I'm not sure what to actually do with Ty::Unknown | 51 | // and I'm not sure what to actually do with Ty::Unknown |
48 | Ty::Unknown => PlaceholderIndex { ui: UniverseIndex::ROOT, idx: 0 }.to_ty(), | 52 | // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty) |
53 | Ty::Unknown => { | ||
54 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty() | ||
55 | } | ||
49 | } | 56 | } |
50 | } | 57 | } |
51 | fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { | 58 | fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { |
@@ -154,7 +161,13 @@ impl ToChalk for GenericPredicate { | |||
154 | GenericPredicate::Implemented(trait_ref) => { | 161 | GenericPredicate::Implemented(trait_ref) => { |
155 | make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) | 162 | make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) |
156 | } | 163 | } |
157 | GenericPredicate::Error => panic!("Trying to pass errored where clause to Chalk"), | 164 | GenericPredicate::Error => { |
165 | let impossible_trait_ref = chalk_ir::TraitRef { | ||
166 | trait_id: UNKNOWN_TRAIT, | ||
167 | parameters: vec![Ty::Unknown.to_chalk(db).cast()], | ||
168 | }; | ||
169 | make_binders(chalk_ir::WhereClause::Implemented(impossible_trait_ref), 0) | ||
170 | } | ||
158 | } | 171 | } |
159 | } | 172 | } |
160 | 173 | ||
@@ -178,19 +191,13 @@ fn convert_where_clauses( | |||
178 | db: &impl HirDatabase, | 191 | db: &impl HirDatabase, |
179 | def: GenericDef, | 192 | def: GenericDef, |
180 | substs: &Substs, | 193 | substs: &Substs, |
181 | ) -> (Vec<chalk_ir::QuantifiedWhereClause>, bool) { | 194 | ) -> Vec<chalk_ir::QuantifiedWhereClause> { |
182 | let generic_predicates = db.generic_predicates(def); | 195 | let generic_predicates = db.generic_predicates(def); |
183 | let mut result = Vec::with_capacity(generic_predicates.len()); | 196 | let mut result = Vec::with_capacity(generic_predicates.len()); |
184 | let mut has_error = false; | ||
185 | for pred in generic_predicates.iter() { | 197 | for pred in generic_predicates.iter() { |
186 | // FIXME: it would probably be nicer if we could just convert errored predicates to a where clause that is never true... | 198 | result.push(pred.clone().subst(substs).to_chalk(db)); |
187 | if pred.is_error() { | ||
188 | has_error = true; | ||
189 | } else { | ||
190 | result.push(pred.clone().subst(substs).to_chalk(db)); | ||
191 | } | ||
192 | } | 199 | } |
193 | (result, has_error) | 200 | result |
194 | } | 201 | } |
195 | 202 | ||
196 | impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> | 203 | impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> |
@@ -202,6 +209,23 @@ where | |||
202 | } | 209 | } |
203 | fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> { | 210 | fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> { |
204 | debug!("trait_datum {:?}", trait_id); | 211 | debug!("trait_datum {:?}", trait_id); |
212 | if trait_id == UNKNOWN_TRAIT { | ||
213 | let trait_datum_bound = chalk_rust_ir::TraitDatumBound { | ||
214 | trait_ref: chalk_ir::TraitRef { | ||
215 | trait_id: UNKNOWN_TRAIT, | ||
216 | parameters: vec![chalk_ir::Ty::BoundVar(0).cast()], | ||
217 | }, | ||
218 | associated_ty_ids: Vec::new(), | ||
219 | where_clauses: Vec::new(), | ||
220 | flags: chalk_rust_ir::TraitFlags { | ||
221 | auto: false, | ||
222 | marker: false, | ||
223 | upstream: true, | ||
224 | fundamental: false, | ||
225 | }, | ||
226 | }; | ||
227 | return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1) }); | ||
228 | } | ||
205 | let trait_: Trait = from_chalk(self.db, trait_id); | 229 | let trait_: Trait = from_chalk(self.db, trait_id); |
206 | let generic_params = trait_.generic_params(self.db); | 230 | let generic_params = trait_.generic_params(self.db); |
207 | let bound_vars = Substs::bound_vars(&generic_params); | 231 | let bound_vars = Substs::bound_vars(&generic_params); |
@@ -213,7 +237,7 @@ where | |||
213 | upstream: trait_.module(self.db).krate(self.db) != Some(self.krate), | 237 | upstream: trait_.module(self.db).krate(self.db) != Some(self.krate), |
214 | fundamental: false, | 238 | fundamental: false, |
215 | }; | 239 | }; |
216 | let (where_clauses, _) = convert_where_clauses(self.db, trait_.into(), &bound_vars); | 240 | let where_clauses = convert_where_clauses(self.db, trait_.into(), &bound_vars); |
217 | let associated_ty_ids = Vec::new(); // FIXME add associated tys | 241 | let associated_ty_ids = Vec::new(); // FIXME add associated tys |
218 | let trait_datum_bound = | 242 | let trait_datum_bound = |
219 | chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; | 243 | chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; |
@@ -241,7 +265,7 @@ where | |||
241 | TypeCtor::Adt(adt) => { | 265 | TypeCtor::Adt(adt) => { |
242 | let generic_params = adt.generic_params(self.db); | 266 | let generic_params = adt.generic_params(self.db); |
243 | let bound_vars = Substs::bound_vars(&generic_params); | 267 | let bound_vars = Substs::bound_vars(&generic_params); |
244 | let (where_clauses, _) = convert_where_clauses(self.db, adt.into(), &bound_vars); | 268 | let where_clauses = convert_where_clauses(self.db, adt.into(), &bound_vars); |
245 | ( | 269 | ( |
246 | generic_params.count_params_including_parent(), | 270 | generic_params.count_params_including_parent(), |
247 | where_clauses, | 271 | where_clauses, |
@@ -281,8 +305,7 @@ where | |||
281 | } else { | 305 | } else { |
282 | chalk_rust_ir::ImplType::External | 306 | chalk_rust_ir::ImplType::External |
283 | }; | 307 | }; |
284 | let (where_clauses, where_clause_error) = | 308 | let where_clauses = convert_where_clauses(self.db, impl_block.into(), &bound_vars); |
285 | convert_where_clauses(self.db, impl_block.into(), &bound_vars); | ||
286 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { | 309 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { |
287 | // FIXME handle negative impls (impl !Sync for Foo) | 310 | // FIXME handle negative impls (impl !Sync for Foo) |
288 | trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)), | 311 | trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)), |
@@ -295,6 +318,9 @@ where | |||
295 | } | 318 | } |
296 | fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> { | 319 | fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> { |
297 | debug!("impls_for_trait {:?}", trait_id); | 320 | debug!("impls_for_trait {:?}", trait_id); |
321 | if trait_id == UNKNOWN_TRAIT { | ||
322 | return Vec::new(); | ||
323 | } | ||
298 | let trait_ = from_chalk(self.db, trait_id); | 324 | let trait_ = from_chalk(self.db, trait_id); |
299 | self.db | 325 | self.db |
300 | .impls_for_trait(self.krate, trait_) | 326 | .impls_for_trait(self.krate, trait_) |