aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2021-05-16 14:50:28 +0100
committerFlorian Diebold <[email protected]>2021-05-21 16:48:34 +0100
commit1250ddc5cf58ff0a6bbf7c07e5bd9f7cc7db5a09 (patch)
tree51c6ed040c2b1ec6b33321501ced866d87701c71 /crates
parenta3d9cac69057db700c4f6e01b84dc59529ea6dfd (diff)
Rework obligation handling
We can't do the easy hack that we did before anymore, where we kept track of whether any inference variables changed since the last time we rechecked obligations. Instead, we store the obligations in canonicalized form; that way we can easily check the inference variables to see whether they have changed since the goal was canonicalized.
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/lib.rs10
-rw-r--r--crates/hir_ty/src/db.rs6
-rw-r--r--crates/hir_ty/src/infer.rs84
-rw-r--r--crates/hir_ty/src/infer/coerce.rs7
-rw-r--r--crates/hir_ty/src/infer/expr.rs6
-rw-r--r--crates/hir_ty/src/infer/path.rs2
-rw-r--r--crates/hir_ty/src/infer/unify.rs173
-rw-r--r--crates/hir_ty/src/lib.rs3
-rw-r--r--crates/hir_ty/src/lower.rs4
-rw-r--r--crates/hir_ty/src/method_resolution.rs48
-rw-r--r--crates/hir_ty/src/traits.rs40
11 files changed, 240 insertions, 143 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 1429384cb..52d72c3c5 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1712,15 +1712,17 @@ impl Type {
1712 resolver: &Resolver, 1712 resolver: &Resolver,
1713 ty: Ty, 1713 ty: Ty,
1714 ) -> Type { 1714 ) -> Type {
1715 let environment = 1715 let environment = resolver
1716 resolver.generic_def().map_or_else(Default::default, |d| db.trait_environment(d)); 1716 .generic_def()
1717 .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
1717 Type { krate, env: environment, ty } 1718 Type { krate, env: environment, ty }
1718 } 1719 }
1719 1720
1720 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { 1721 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type {
1721 let resolver = lexical_env.resolver(db.upcast()); 1722 let resolver = lexical_env.resolver(db.upcast());
1722 let environment = 1723 let environment = resolver
1723 resolver.generic_def().map_or_else(Default::default, |d| db.trait_environment(d)); 1724 .generic_def()
1725 .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
1724 Type { krate, env: environment, ty } 1726 Type { krate, env: environment, ty }
1725 } 1727 }
1726 1728
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index f773aa621..be5b9110e 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -134,14 +134,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
134 fn trait_solve( 134 fn trait_solve(
135 &self, 135 &self,
136 krate: CrateId, 136 krate: CrateId,
137 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, 137 goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
138 ) -> Option<crate::Solution>; 138 ) -> Option<crate::Solution>;
139 139
140 #[salsa::invoke(crate::traits::trait_solve_query)] 140 #[salsa::invoke(crate::traits::trait_solve_query)]
141 fn trait_solve_query( 141 fn trait_solve_query(
142 &self, 142 &self,
143 krate: CrateId, 143 krate: CrateId,
144 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, 144 goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
145 ) -> Option<crate::Solution>; 145 ) -> Option<crate::Solution>;
146 146
147 #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)] 147 #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)]
@@ -168,7 +168,7 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
168fn trait_solve_wait( 168fn trait_solve_wait(
169 db: &dyn HirDatabase, 169 db: &dyn HirDatabase,
170 krate: CrateId, 170 krate: CrateId,
171 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, 171 goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
172) -> Option<crate::Solution> { 172) -> Option<crate::Solution> {
173 let _p = profile::span("trait_solve::wait"); 173 let _p = profile::span("trait_solve::wait");
174 db.trait_solve_query(krate, goal) 174 db.trait_solve_query(krate, goal)
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 7898740be..97e7c5f8c 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -14,7 +14,7 @@
14//! the `ena` crate, which is extracted from rustc. 14//! the `ena` crate, which is extracted from rustc.
15 15
16use std::borrow::Cow; 16use std::borrow::Cow;
17use std::mem; 17
18use std::ops::Index; 18use std::ops::Index;
19use std::sync::Arc; 19use std::sync::Arc;
20 20
@@ -27,8 +27,8 @@ use hir_def::{
27 path::{path, Path}, 27 path::{path, Path},
28 resolver::{HasResolver, Resolver, TypeNs}, 28 resolver::{HasResolver, Resolver, TypeNs},
29 type_ref::TypeRef, 29 type_ref::TypeRef,
30 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, Lookup, TraitId, 30 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
31 TypeAliasId, VariantId, 31 TraitId, TypeAliasId, VariantId,
32}; 32};
33use hir_expand::{diagnostics::DiagnosticSink, name::name}; 33use hir_expand::{diagnostics::DiagnosticSink, name::name};
34use la_arena::ArenaMap; 34use la_arena::ArenaMap;
@@ -36,13 +36,11 @@ use rustc_hash::FxHashMap;
36use stdx::impl_from; 36use stdx::impl_from;
37use syntax::SmolStr; 37use syntax::SmolStr;
38 38
39use super::{ 39use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty};
40 DomainGoal, Guidance, InEnvironment, ProjectionTy, Solution, TraitEnvironment, TraitRef, Ty,
41};
42use crate::{ 40use crate::{
43 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic, 41 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic,
44 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner, 42 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Interner, TyBuilder, TyExt,
45 TyBuilder, TyExt, TyKind, 43 TyKind,
46}; 44};
47 45
48// This lint has a false positive here. See the link below for details. 46// This lint has a false positive here. See the link below for details.
@@ -227,8 +225,6 @@ struct InferenceContext<'a> {
227 resolver: Resolver, 225 resolver: Resolver,
228 table: unify::InferenceTable<'a>, 226 table: unify::InferenceTable<'a>,
229 trait_env: Arc<TraitEnvironment>, 227 trait_env: Arc<TraitEnvironment>,
230 obligations: Vec<DomainGoal>,
231 last_obligations_check: Option<u32>,
232 result: InferenceResult, 228 result: InferenceResult,
233 /// The return type of the function being inferred, or the closure if we're 229 /// The return type of the function being inferred, or the closure if we're
234 /// currently within one. 230 /// currently within one.
@@ -260,15 +256,15 @@ fn find_breakable<'c>(
260 256
261impl<'a> InferenceContext<'a> { 257impl<'a> InferenceContext<'a> {
262 fn new(db: &'a dyn HirDatabase, owner: DefWithBodyId, resolver: Resolver) -> Self { 258 fn new(db: &'a dyn HirDatabase, owner: DefWithBodyId, resolver: Resolver) -> Self {
263 let trait_env = 259 let krate = owner.module(db.upcast()).krate();
264 owner.as_generic_def_id().map_or_else(Default::default, |d| db.trait_environment(d)); 260 let trait_env = owner
261 .as_generic_def_id()
262 .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
265 InferenceContext { 263 InferenceContext {
266 result: InferenceResult::default(), 264 result: InferenceResult::default(),
267 table: unify::InferenceTable::new(db, trait_env.clone()), 265 table: unify::InferenceTable::new(db, trait_env.clone()),
268 obligations: Vec::default(),
269 last_obligations_check: None,
270 return_ty: TyKind::Error.intern(&Interner), // set in collect_fn_signature
271 trait_env, 266 trait_env,
267 return_ty: TyKind::Error.intern(&Interner), // set in collect_fn_signature
272 db, 268 db,
273 owner, 269 owner,
274 body: db.body(owner), 270 body: db.body(owner),
@@ -284,6 +280,7 @@ impl<'a> InferenceContext<'a> {
284 280
285 fn resolve_all(mut self) -> InferenceResult { 281 fn resolve_all(mut self) -> InferenceResult {
286 // FIXME resolve obligations as well (use Guidance if necessary) 282 // FIXME resolve obligations as well (use Guidance if necessary)
283 self.table.resolve_obligations_as_possible();
287 284
288 // make sure diverging type variables are marked as such 285 // make sure diverging type variables are marked as such
289 self.table.propagate_diverging_flag(); 286 self.table.propagate_diverging_flag();
@@ -357,44 +354,11 @@ impl<'a> InferenceContext<'a> {
357 } 354 }
358 355
359 fn resolve_obligations_as_possible(&mut self) { 356 fn resolve_obligations_as_possible(&mut self) {
360 let _span = profile::span("resolve_obligations_as_possible"); 357 self.table.resolve_obligations_as_possible();
361
362 let obligations = mem::replace(&mut self.obligations, Vec::new());
363 for obligation in obligations {
364 let in_env = InEnvironment::new(&self.trait_env.env, obligation.clone());
365 let canonicalized = self.canonicalize(in_env);
366 let solution =
367 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone());
368
369 match solution {
370 Some(Solution::Unique(canonical_subst)) => {
371 canonicalized.apply_solution(
372 self,
373 Canonical {
374 binders: canonical_subst.binders,
375 // FIXME: handle constraints
376 value: canonical_subst.value.subst,
377 },
378 );
379 }
380 Some(Solution::Ambig(Guidance::Definite(substs))) => {
381 canonicalized.apply_solution(self, substs);
382 self.obligations.push(obligation);
383 }
384 Some(_) => {
385 // FIXME use this when trying to resolve everything at the end
386 self.obligations.push(obligation);
387 }
388 None => {
389 // FIXME obligation cannot be fulfilled => diagnostic
390 }
391 };
392 }
393 } 358 }
394 359
395 fn push_obligation(&mut self, o: DomainGoal) { 360 fn push_obligation(&mut self, o: DomainGoal) {
396 self.obligations.push(o); 361 self.table.register_obligation(o.cast(&Interner));
397 self.last_obligations_check = None;
398 } 362 }
399 363
400 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 364 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
@@ -467,25 +431,7 @@ impl<'a> InferenceContext<'a> {
467 /// call). `make_ty` handles this already, but e.g. for field types we need 431 /// call). `make_ty` handles this already, but e.g. for field types we need
468 /// to do it as well. 432 /// to do it as well.
469 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { 433 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
470 let ty = self.resolve_ty_as_possible(ty); 434 self.table.normalize_associated_types_in(ty)
471 fold_tys(
472 ty,
473 |ty, _| match ty.kind(&Interner) {
474 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
475 self.normalize_projection_ty(proj_ty.clone())
476 }
477 _ => ty,
478 },
479 DebruijnIndex::INNERMOST,
480 )
481 }
482
483 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
484 let var = self.table.new_type_var();
485 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
486 let obligation = alias_eq.cast(&Interner);
487 self.push_obligation(obligation);
488 var
489 } 435 }
490 436
491 fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantId>) { 437 fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantId>) {
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index 4d80b4a08..911343cb9 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -402,12 +402,15 @@ impl<'a> InferenceContext<'a> {
402 // solve `CoerceUnsized` and `Unsize` goals at this point and leaves the 402 // solve `CoerceUnsized` and `Unsize` goals at this point and leaves the
403 // rest for later. Also, there's some logic about sized type variables. 403 // rest for later. Also, there's some logic about sized type variables.
404 // Need to find out in what cases this is necessary 404 // Need to find out in what cases this is necessary
405 let solution = self.db.trait_solve(krate, canonicalized.value.clone()).ok_or(TypeError)?; 405 let solution = self
406 .db
407 .trait_solve(krate, canonicalized.value.clone().cast(&Interner))
408 .ok_or(TypeError)?;
406 409
407 match solution { 410 match solution {
408 Solution::Unique(v) => { 411 Solution::Unique(v) => {
409 canonicalized.apply_solution( 412 canonicalized.apply_solution(
410 self, 413 &mut self.table,
411 Canonical { 414 Canonical {
412 binders: v.binders, 415 binders: v.binders,
413 // FIXME handle constraints 416 // FIXME handle constraints
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index f439169ea..6eaccd9b4 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -99,9 +99,9 @@ impl<'a> InferenceContext<'a> {
99 environment: trait_env, 99 environment: trait_env,
100 }; 100 };
101 let canonical = self.canonicalize(obligation.clone()); 101 let canonical = self.canonicalize(obligation.clone());
102 if self.db.trait_solve(krate, canonical.value).is_some() { 102 if self.db.trait_solve(krate, canonical.value.cast(&Interner)).is_some() {
103 self.push_obligation(obligation.goal); 103 self.push_obligation(obligation.goal);
104 let return_ty = self.normalize_projection_ty(projection); 104 let return_ty = self.table.normalize_projection_ty(projection);
105 Some((arg_tys, return_ty)) 105 Some((arg_tys, return_ty))
106 } else { 106 } else {
107 None 107 None
@@ -306,7 +306,7 @@ impl<'a> InferenceContext<'a> {
306 self.resolver.krate(), 306 self.resolver.krate(),
307 InEnvironment { 307 InEnvironment {
308 goal: canonicalized.value.clone(), 308 goal: canonicalized.value.clone(),
309 environment: self.trait_env.env.clone(), 309 environment: self.table.trait_env.env.clone(),
310 }, 310 },
311 ); 311 );
312 let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs 312 let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index bc64b612b..fd366e121 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -225,7 +225,7 @@ impl<'a> InferenceContext<'a> {
225 method_resolution::iterate_method_candidates( 225 method_resolution::iterate_method_candidates(
226 &canonical_ty.value, 226 &canonical_ty.value,
227 self.db, 227 self.db,
228 self.trait_env.clone(), 228 self.table.trait_env.clone(),
229 krate, 229 krate,
230 &traits_in_scope, 230 &traits_in_scope,
231 None, 231 None,
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 93cd54f0d..75e04e8b5 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -1,6 +1,6 @@
1//! Unification and canonicalization logic. 1//! Unification and canonicalization logic.
2 2
3use std::{borrow::Cow, fmt, sync::Arc}; 3use std::{borrow::Cow, fmt, mem, sync::Arc};
4 4
5use chalk_ir::{ 5use chalk_ir::{
6 cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, TyVariableKind, 6 cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, TyVariableKind,
@@ -11,8 +11,9 @@ use ena::unify::UnifyKey;
11 11
12use super::{InferOk, InferResult, InferenceContext, TypeError}; 12use super::{InferOk, InferResult, InferenceContext, TypeError};
13use crate::{ 13use crate::{
14 db::HirDatabase, fold_tys, static_lifetime, BoundVar, Canonical, DebruijnIndex, GenericArg, 14 db::HirDatabase, fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical,
15 InferenceVar, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyKind, VariableKind, 15 DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar, Interner, ProjectionTy,
16 Scalar, Solution, Substitution, TraitEnvironment, Ty, TyKind, VariableKind,
16}; 17};
17 18
18impl<'a> InferenceContext<'a> { 19impl<'a> InferenceContext<'a> {
@@ -23,17 +24,11 @@ impl<'a> InferenceContext<'a> {
23 where 24 where
24 T::Result: HasInterner<Interner = Interner>, 25 T::Result: HasInterner<Interner = Interner>,
25 { 26 {
26 let result = self.table.var_unification_table.canonicalize(&Interner, t); 27 self.table.canonicalize(t)
27 let free_vars = result
28 .free_vars
29 .into_iter()
30 .map(|free_var| free_var.to_generic_arg(&Interner))
31 .collect();
32 Canonicalized { value: result.quantified, free_vars }
33 } 28 }
34} 29}
35 30
36#[derive(Debug)] 31#[derive(Debug, Clone)]
37pub(super) struct Canonicalized<T> 32pub(super) struct Canonicalized<T>
38where 33where
39 T: HasInterner<Interner = Interner>, 34 T: HasInterner<Interner = Interner>,
@@ -49,22 +44,16 @@ impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
49 44
50 pub(super) fn apply_solution( 45 pub(super) fn apply_solution(
51 &self, 46 &self,
52 ctx: &mut InferenceContext<'_>, 47 ctx: &mut InferenceTable,
53 solution: Canonical<Substitution>, 48 solution: Canonical<Substitution>,
54 ) { 49 ) {
55 // the solution may contain new variables, which we need to convert to new inference vars 50 // the solution may contain new variables, which we need to convert to new inference vars
56 let new_vars = Substitution::from_iter( 51 let new_vars = Substitution::from_iter(
57 &Interner, 52 &Interner,
58 solution.binders.iter(&Interner).map(|k| match k.kind { 53 solution.binders.iter(&Interner).map(|k| match k.kind {
59 VariableKind::Ty(TyVariableKind::General) => { 54 VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(&Interner),
60 ctx.table.new_type_var().cast(&Interner) 55 VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(&Interner),
61 } 56 VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(&Interner),
62 VariableKind::Ty(TyVariableKind::Integer) => {
63 ctx.table.new_integer_var().cast(&Interner)
64 }
65 VariableKind::Ty(TyVariableKind::Float) => {
66 ctx.table.new_float_var().cast(&Interner)
67 }
68 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere 57 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
69 VariableKind::Lifetime => static_lifetime().cast(&Interner), 58 VariableKind::Lifetime => static_lifetime().cast(&Interner),
70 _ => panic!("const variable in solution"), 59 _ => panic!("const variable in solution"),
@@ -76,9 +65,9 @@ impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
76 // eagerly replace projections in the type; we may be getting types 65 // eagerly replace projections in the type; we may be getting types
77 // e.g. from where clauses where this hasn't happened yet 66 // e.g. from where clauses where this hasn't happened yet
78 let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), &Interner)); 67 let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), &Interner));
79 ctx.table.unify(var.assert_ty_ref(&Interner), &ty); 68 ctx.unify(var.assert_ty_ref(&Interner), &ty);
80 } else { 69 } else {
81 let _ = ctx.table.unify_inner(&var, &new_vars.apply(v.clone(), &Interner)); 70 let _ = ctx.unify_inner(&var, &new_vars.apply(v.clone(), &Interner));
82 } 71 }
83 } 72 }
84 } 73 }
@@ -167,10 +156,11 @@ type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
167 156
168#[derive(Clone)] 157#[derive(Clone)]
169pub(crate) struct InferenceTable<'a> { 158pub(crate) struct InferenceTable<'a> {
170 db: &'a dyn HirDatabase, 159 pub db: &'a dyn HirDatabase,
171 trait_env: Arc<TraitEnvironment>, 160 pub trait_env: Arc<TraitEnvironment>,
172 pub(super) var_unification_table: ChalkInferenceTable, 161 pub(super) var_unification_table: ChalkInferenceTable,
173 pub(super) type_variable_table: TypeVariableTable, 162 pub(super) type_variable_table: TypeVariableTable,
163 pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
174} 164}
175 165
176impl<'a> InferenceTable<'a> { 166impl<'a> InferenceTable<'a> {
@@ -180,6 +170,7 @@ impl<'a> InferenceTable<'a> {
180 trait_env, 170 trait_env,
181 var_unification_table: ChalkInferenceTable::new(), 171 var_unification_table: ChalkInferenceTable::new(),
182 type_variable_table: TypeVariableTable { inner: Vec::new() }, 172 type_variable_table: TypeVariableTable { inner: Vec::new() },
173 pending_obligations: Vec::new(),
183 } 174 }
184 } 175 }
185 176
@@ -202,6 +193,50 @@ impl<'a> InferenceTable<'a> {
202 } 193 }
203 } 194 }
204 195
196 pub(super) fn canonicalize<T: Fold<Interner> + HasInterner<Interner = Interner>>(
197 &mut self,
198 t: T,
199 ) -> Canonicalized<T::Result>
200 where
201 T::Result: HasInterner<Interner = Interner>,
202 {
203 let result = self.var_unification_table.canonicalize(&Interner, t);
204 let free_vars = result
205 .free_vars
206 .into_iter()
207 .map(|free_var| free_var.to_generic_arg(&Interner))
208 .collect();
209 Canonicalized { value: result.quantified, free_vars }
210 }
211
212 /// Recurses through the given type, normalizing associated types mentioned
213 /// in it by replacing them by type variables and registering obligations to
214 /// resolve later. This should be done once for every type we get from some
215 /// type annotation (e.g. from a let type annotation, field type or function
216 /// call). `make_ty` handles this already, but e.g. for field types we need
217 /// to do it as well.
218 pub(super) fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
219 let ty = self.resolve_ty_as_possible(ty);
220 fold_tys(
221 ty,
222 |ty, _| match ty.kind(&Interner) {
223 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
224 self.normalize_projection_ty(proj_ty.clone())
225 }
226 _ => ty,
227 },
228 DebruijnIndex::INNERMOST,
229 )
230 }
231
232 pub(super) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
233 let var = self.new_type_var();
234 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
235 let obligation = alias_eq.cast(&Interner);
236 self.register_obligation(obligation);
237 var
238 }
239
205 fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty { 240 fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
206 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT); 241 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
207 // Chalk might have created some type variables for its own purposes that we don't know about... 242 // Chalk might have created some type variables for its own purposes that we don't know about...
@@ -341,6 +376,94 @@ impl<'a> InferenceTable<'a> {
341 DebruijnIndex::INNERMOST, 376 DebruijnIndex::INNERMOST,
342 ) 377 )
343 } 378 }
379
380 pub fn register_obligation(&mut self, goal: Goal) {
381 let in_env = InEnvironment::new(&self.trait_env.env, goal);
382 self.register_obligation_in_env(in_env)
383 }
384
385 fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) {
386 let canonicalized = self.canonicalize(goal);
387 if !self.try_resolve_obligation(&canonicalized) {
388 self.pending_obligations.push(canonicalized);
389 }
390 }
391
392 pub fn resolve_obligations_as_possible(&mut self) {
393 let _span = profile::span("resolve_obligations_as_possible");
394 let mut changed = true;
395 let mut obligations = Vec::new();
396 while changed {
397 changed = false;
398 mem::swap(&mut self.pending_obligations, &mut obligations);
399 for canonicalized in obligations.drain(..) {
400 if !self.check_changed(&canonicalized) {
401 self.pending_obligations.push(canonicalized);
402 continue;
403 }
404 changed = true;
405 let uncanonical = chalk_ir::Substitute::apply(
406 &canonicalized.free_vars,
407 canonicalized.value.value,
408 &Interner,
409 );
410 self.register_obligation_in_env(uncanonical);
411 }
412 }
413 }
414
415 /// This checks whether any of the free variables in the `canonicalized`
416 /// have changed (either been unified with another variable, or with a
417 /// value). If this is not the case, we don't need to try to solve the goal
418 /// again -- it'll give the same result as last time.
419 fn check_changed(&mut self, canonicalized: &Canonicalized<InEnvironment<Goal>>) -> bool {
420 canonicalized.free_vars.iter().any(|var| {
421 let iv = match var.data(&Interner) {
422 chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(&Interner),
423 chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(&Interner),
424 chalk_ir::GenericArgData::Const(c) => c.inference_var(&Interner),
425 }
426 .expect("free var is not inference var");
427 if self.var_unification_table.probe_var(iv).is_some() {
428 return true;
429 }
430 let root = self.var_unification_table.inference_var_root(iv);
431 iv != root
432 })
433 }
434
435 fn try_resolve_obligation(
436 &mut self,
437 canonicalized: &Canonicalized<InEnvironment<Goal>>,
438 ) -> bool {
439 let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value.clone());
440
441 match solution {
442 Some(Solution::Unique(canonical_subst)) => {
443 canonicalized.apply_solution(
444 self,
445 Canonical {
446 binders: canonical_subst.binders,
447 // FIXME: handle constraints
448 value: canonical_subst.value.subst,
449 },
450 );
451 true
452 }
453 Some(Solution::Ambig(Guidance::Definite(substs))) => {
454 canonicalized.apply_solution(self, substs);
455 false
456 }
457 Some(_) => {
458 // FIXME use this when trying to resolve everything at the end
459 false
460 }
461 None => {
462 // FIXME obligation cannot be fulfilled => diagnostic
463 true
464 }
465 }
466 }
344} 467}
345 468
346impl<'a> fmt::Debug for InferenceTable<'a> { 469impl<'a> fmt::Debug for InferenceTable<'a> {
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 56f60c46b..72093d75a 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -45,7 +45,7 @@ use hir_def::{
45}; 45};
46use stdx::always; 46use stdx::always;
47 47
48use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; 48use crate::{db::HirDatabase, utils::generics};
49 49
50pub use autoderef::autoderef; 50pub use autoderef::autoderef;
51pub use builder::TyBuilder; 51pub use builder::TyBuilder;
@@ -114,6 +114,7 @@ pub type FnSig = chalk_ir::FnSig<Interner>;
114 114
115pub type InEnvironment<T> = chalk_ir::InEnvironment<T>; 115pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
116pub type DomainGoal = chalk_ir::DomainGoal<Interner>; 116pub type DomainGoal = chalk_ir::DomainGoal<Interner>;
117pub type Goal = chalk_ir::Goal<Interner>;
117pub type AliasEq = chalk_ir::AliasEq<Interner>; 118pub type AliasEq = chalk_ir::AliasEq<Interner>;
118pub type Solution = chalk_solve::Solution<Interner>; 119pub type Solution = chalk_solve::Solution<Interner>;
119pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>; 120pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index bd8bb6028..8a375b973 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -1035,9 +1035,11 @@ pub(crate) fn trait_environment_query(
1035 clauses.push(program_clause.into_from_env_clause(&Interner)); 1035 clauses.push(program_clause.into_from_env_clause(&Interner));
1036 } 1036 }
1037 1037
1038 let krate = def.module(db.upcast()).krate();
1039
1038 let env = chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses); 1040 let env = chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses);
1039 1041
1040 Arc::new(TraitEnvironment { traits_from_clauses: traits_in_scope, env }) 1042 Arc::new(TraitEnvironment { krate, traits_from_clauses: traits_in_scope, env })
1041} 1043}
1042 1044
1043/// Resolve the where clause(s) of an item with generics. 1045/// Resolve the where clause(s) of an item with generics.
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 37e1f89d8..08e385a42 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -577,6 +577,7 @@ fn iterate_method_candidates_by_receiver(
577 if iterate_inherent_methods( 577 if iterate_inherent_methods(
578 self_ty, 578 self_ty,
579 db, 579 db,
580 env.clone(),
580 name, 581 name,
581 Some(receiver_ty), 582 Some(receiver_ty),
582 krate, 583 krate,
@@ -613,8 +614,16 @@ fn iterate_method_candidates_for_self_ty(
613 name: Option<&Name>, 614 name: Option<&Name>,
614 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, 615 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
615) -> bool { 616) -> bool {
616 if iterate_inherent_methods(self_ty, db, name, None, krate, visible_from_module, &mut callback) 617 if iterate_inherent_methods(
617 { 618 self_ty,
619 db,
620 env.clone(),
621 name,
622 None,
623 krate,
624 visible_from_module,
625 &mut callback,
626 ) {
618 return true; 627 return true;
619 } 628 }
620 iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback) 629 iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback)
@@ -653,12 +662,12 @@ fn iterate_trait_method_candidates(
653 for (_name, item) in data.items.iter() { 662 for (_name, item) in data.items.iter() {
654 // Don't pass a `visible_from_module` down to `is_valid_candidate`, 663 // Don't pass a `visible_from_module` down to `is_valid_candidate`,
655 // since only inherent methods should be included into visibility checking. 664 // since only inherent methods should be included into visibility checking.
656 if !is_valid_candidate(db, name, receiver_ty, *item, self_ty, None) { 665 if !is_valid_candidate(db, env.clone(), name, receiver_ty, *item, self_ty, None) {
657 continue; 666 continue;
658 } 667 }
659 if !known_implemented { 668 if !known_implemented {
660 let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone()); 669 let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone());
661 if db.trait_solve(krate, goal).is_none() { 670 if db.trait_solve(krate, goal.cast(&Interner)).is_none() {
662 continue 'traits; 671 continue 'traits;
663 } 672 }
664 } 673 }
@@ -675,6 +684,7 @@ fn iterate_trait_method_candidates(
675fn iterate_inherent_methods( 684fn iterate_inherent_methods(
676 self_ty: &Canonical<Ty>, 685 self_ty: &Canonical<Ty>,
677 db: &dyn HirDatabase, 686 db: &dyn HirDatabase,
687 env: Arc<TraitEnvironment>,
678 name: Option<&Name>, 688 name: Option<&Name>,
679 receiver_ty: Option<&Canonical<Ty>>, 689 receiver_ty: Option<&Canonical<Ty>>,
680 krate: CrateId, 690 krate: CrateId,
@@ -690,14 +700,24 @@ fn iterate_inherent_methods(
690 700
691 for &impl_def in impls.for_self_ty(&self_ty.value) { 701 for &impl_def in impls.for_self_ty(&self_ty.value) {
692 for &item in db.impl_data(impl_def).items.iter() { 702 for &item in db.impl_data(impl_def).items.iter() {
693 if !is_valid_candidate(db, name, receiver_ty, item, self_ty, visible_from_module) { 703 if !is_valid_candidate(
704 db,
705 env.clone(),
706 name,
707 receiver_ty,
708 item,
709 self_ty,
710 visible_from_module,
711 ) {
694 continue; 712 continue;
695 } 713 }
696 // we have to check whether the self type unifies with the type 714 // we have to check whether the self type unifies with the type
697 // that the impl is for. If we have a receiver type, this 715 // that the impl is for. If we have a receiver type, this
698 // already happens in `is_valid_candidate` above; if not, we 716 // already happens in `is_valid_candidate` above; if not, we
699 // check it here 717 // check it here
700 if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { 718 if receiver_ty.is_none()
719 && inherent_impl_substs(db, env.clone(), impl_def, self_ty).is_none()
720 {
701 cov_mark::hit!(impl_self_type_match_without_receiver); 721 cov_mark::hit!(impl_self_type_match_without_receiver);
702 continue; 722 continue;
703 } 723 }
@@ -722,7 +742,7 @@ pub fn resolve_indexing_op(
722 let deref_chain = autoderef_method_receiver(db, krate, ty); 742 let deref_chain = autoderef_method_receiver(db, krate, ty);
723 for ty in deref_chain { 743 for ty in deref_chain {
724 let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone()); 744 let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone());
725 if db.trait_solve(krate, goal).is_some() { 745 if db.trait_solve(krate, goal.cast(&Interner)).is_some() {
726 return Some(ty); 746 return Some(ty);
727 } 747 }
728 } 748 }
@@ -731,6 +751,7 @@ pub fn resolve_indexing_op(
731 751
732fn is_valid_candidate( 752fn is_valid_candidate(
733 db: &dyn HirDatabase, 753 db: &dyn HirDatabase,
754 env: Arc<TraitEnvironment>,
734 name: Option<&Name>, 755 name: Option<&Name>,
735 receiver_ty: Option<&Canonical<Ty>>, 756 receiver_ty: Option<&Canonical<Ty>>,
736 item: AssocItemId, 757 item: AssocItemId,
@@ -749,7 +770,7 @@ fn is_valid_candidate(
749 if !data.has_self_param() { 770 if !data.has_self_param() {
750 return false; 771 return false;
751 } 772 }
752 let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) { 773 let transformed_receiver_ty = match transform_receiver_ty(db, env, m, self_ty) {
753 Some(ty) => ty, 774 Some(ty) => ty,
754 None => return false, 775 None => return false,
755 }; 776 };
@@ -776,6 +797,7 @@ fn is_valid_candidate(
776 797
777pub(crate) fn inherent_impl_substs( 798pub(crate) fn inherent_impl_substs(
778 db: &dyn HirDatabase, 799 db: &dyn HirDatabase,
800 env: Arc<TraitEnvironment>,
779 impl_id: ImplId, 801 impl_id: ImplId,
780 self_ty: &Canonical<Ty>, 802 self_ty: &Canonical<Ty>,
781) -> Option<Substitution> { 803) -> Option<Substitution> {
@@ -798,8 +820,7 @@ pub(crate) fn inherent_impl_substs(
798 binders: CanonicalVarKinds::from_iter(&Interner, kinds), 820 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
799 value: (self_ty_with_vars, self_ty.value.clone()), 821 value: (self_ty_with_vars, self_ty.value.clone()),
800 }; 822 };
801 let trait_env = Arc::new(TraitEnvironment::default()); // FIXME 823 let substs = super::infer::unify(db, env, &tys)?;
802 let substs = super::infer::unify(db, trait_env, &tys)?;
803 // We only want the substs for the vars we added, not the ones from self_ty. 824 // We only want the substs for the vars we added, not the ones from self_ty.
804 // Also, if any of the vars we added are still in there, we replace them by 825 // Also, if any of the vars we added are still in there, we replace them by
805 // Unknown. I think this can only really happen if self_ty contained 826 // Unknown. I think this can only really happen if self_ty contained
@@ -824,6 +845,7 @@ fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution
824 845
825fn transform_receiver_ty( 846fn transform_receiver_ty(
826 db: &dyn HirDatabase, 847 db: &dyn HirDatabase,
848 env: Arc<TraitEnvironment>,
827 function_id: FunctionId, 849 function_id: FunctionId,
828 self_ty: &Canonical<Ty>, 850 self_ty: &Canonical<Ty>,
829) -> Option<Ty> { 851) -> Option<Ty> {
@@ -833,7 +855,7 @@ fn transform_receiver_ty(
833 .fill_with_unknown() 855 .fill_with_unknown()
834 .build(), 856 .build(),
835 AssocContainerId::ImplId(impl_id) => { 857 AssocContainerId::ImplId(impl_id) => {
836 let impl_substs = inherent_impl_substs(db, impl_id, &self_ty)?; 858 let impl_substs = inherent_impl_substs(db, env, impl_id, &self_ty)?;
837 TyBuilder::subst_for_def(db, function_id) 859 TyBuilder::subst_for_def(db, function_id)
838 .use_parent_substs(&impl_substs) 860 .use_parent_substs(&impl_substs)
839 .fill_with_unknown() 861 .fill_with_unknown()
@@ -853,7 +875,7 @@ pub fn implements_trait(
853 trait_: TraitId, 875 trait_: TraitId,
854) -> bool { 876) -> bool {
855 let goal = generic_implements_goal(db, env, trait_, ty.clone()); 877 let goal = generic_implements_goal(db, env, trait_, ty.clone());
856 let solution = db.trait_solve(krate, goal); 878 let solution = db.trait_solve(krate, goal.cast(&Interner));
857 879
858 solution.is_some() 880 solution.is_some()
859} 881}
@@ -866,7 +888,7 @@ pub fn implements_trait_unique(
866 trait_: TraitId, 888 trait_: TraitId,
867) -> bool { 889) -> bool {
868 let goal = generic_implements_goal(db, env, trait_, ty.clone()); 890 let goal = generic_implements_goal(db, env, trait_, ty.clone());
869 let solution = db.trait_solve(krate, goal); 891 let solution = db.trait_solve(krate, goal.cast(&Interner));
870 892
871 matches!(solution, Some(crate::Solution::Unique(_))) 893 matches!(solution, Some(crate::Solution::Unique(_)))
872} 894}
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index 9936d0803..294cb531c 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -2,7 +2,7 @@
2 2
3use std::env::var; 3use std::env::var;
4 4
5use chalk_ir::cast::Cast; 5use chalk_ir::GoalData;
6use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver}; 6use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
7 7
8use base_db::CrateId; 8use base_db::CrateId;
@@ -10,7 +10,7 @@ use hir_def::{lang_item::LangItemTarget, TraitId};
10use stdx::panic_context; 10use stdx::panic_context;
11 11
12use crate::{ 12use crate::{
13 db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment, 13 db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
14 Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause, 14 Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
15}; 15};
16 16
@@ -38,6 +38,7 @@ fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
38/// we assume that `T: Default`. 38/// we assume that `T: Default`.
39#[derive(Debug, Clone, PartialEq, Eq, Hash)] 39#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40pub struct TraitEnvironment { 40pub struct TraitEnvironment {
41 pub krate: CrateId,
41 // When we're using Chalk's Ty we can make this a BTreeMap since it's Ord, 42 // When we're using Chalk's Ty we can make this a BTreeMap since it's Ord,
42 // but for now it's too annoying... 43 // but for now it's too annoying...
43 pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>, 44 pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
@@ -45,6 +46,14 @@ pub struct TraitEnvironment {
45} 46}
46 47
47impl TraitEnvironment { 48impl TraitEnvironment {
49 pub fn empty(krate: CrateId) -> Self {
50 TraitEnvironment {
51 krate,
52 traits_from_clauses: Vec::new(),
53 env: chalk_ir::Environment::new(&Interner),
54 }
55 }
56
48 pub(crate) fn traits_in_scope_from_clauses<'a>( 57 pub(crate) fn traits_in_scope_from_clauses<'a>(
49 &'a self, 58 &'a self,
50 ty: &'a Ty, 59 ty: &'a Ty,
@@ -59,34 +68,25 @@ impl TraitEnvironment {
59 } 68 }
60} 69}
61 70
62impl Default for TraitEnvironment {
63 fn default() -> Self {
64 TraitEnvironment {
65 traits_from_clauses: Vec::new(),
66 env: chalk_ir::Environment::new(&Interner),
67 }
68 }
69}
70
71/// Solve a trait goal using Chalk. 71/// Solve a trait goal using Chalk.
72pub(crate) fn trait_solve_query( 72pub(crate) fn trait_solve_query(
73 db: &dyn HirDatabase, 73 db: &dyn HirDatabase,
74 krate: CrateId, 74 krate: CrateId,
75 goal: Canonical<InEnvironment<DomainGoal>>, 75 goal: Canonical<InEnvironment<Goal>>,
76) -> Option<Solution> { 76) -> Option<Solution> {
77 let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal { 77 let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(&Interner) {
78 DomainGoal::Holds(WhereClause::Implemented(it)) => { 78 GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
79 db.trait_data(it.hir_trait_id()).name.to_string() 79 db.trait_data(it.hir_trait_id()).name.to_string()
80 } 80 }
81 DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(), 81 GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
82 _ => "??".to_string(), 82 _ => "??".to_string(),
83 }); 83 });
84 log::info!("trait_solve_query({})", goal.value.goal.display(db)); 84 log::info!("trait_solve_query({:?})", goal.value.goal);
85 85
86 if let DomainGoal::Holds(WhereClause::AliasEq(AliasEq { 86 if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
87 alias: AliasTy::Projection(projection_ty), 87 alias: AliasTy::Projection(projection_ty),
88 .. 88 ..
89 })) = &goal.value.goal 89 }))) = &goal.value.goal.data(&Interner)
90 { 90 {
91 if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(&Interner).kind(&Interner) { 91 if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(&Interner).kind(&Interner) {
92 // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible 92 // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
@@ -94,11 +94,9 @@ pub(crate) fn trait_solve_query(
94 } 94 }
95 } 95 }
96 96
97 let canonical = goal.cast(&Interner);
98
99 // We currently don't deal with universes (I think / hope they're not yet 97 // We currently don't deal with universes (I think / hope they're not yet
100 // relevant for our use cases?) 98 // relevant for our use cases?)
101 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; 99 let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
102 solve(db, krate, &u_canonical) 100 solve(db, krate, &u_canonical)
103} 101}
104 102