aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_ty/src/infer.rs20
-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.rs8
-rw-r--r--crates/hir_ty/src/lower.rs69
-rw-r--r--docs/dev/style.md45
6 files changed, 103 insertions, 47 deletions
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index e4407ff50..674e9e6f9 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -210,6 +210,7 @@ struct InferenceContext<'a> {
210 table: unify::InferenceTable, 210 table: unify::InferenceTable,
211 trait_env: Arc<TraitEnvironment>, 211 trait_env: Arc<TraitEnvironment>,
212 obligations: Vec<DomainGoal>, 212 obligations: Vec<DomainGoal>,
213 last_obligations_check: Option<u32>,
213 result: InferenceResult, 214 result: InferenceResult,
214 /// The return type of the function being inferred, or the closure if we're 215 /// The return type of the function being inferred, or the closure if we're
215 /// currently within one. 216 /// currently within one.
@@ -245,6 +246,7 @@ impl<'a> InferenceContext<'a> {
245 result: InferenceResult::default(), 246 result: InferenceResult::default(),
246 table: unify::InferenceTable::new(), 247 table: unify::InferenceTable::new(),
247 obligations: Vec::default(), 248 obligations: Vec::default(),
249 last_obligations_check: None,
248 return_ty: TyKind::Unknown.intern(&Interner), // set in collect_fn_signature 250 return_ty: TyKind::Unknown.intern(&Interner), // set in collect_fn_signature
249 trait_env: owner 251 trait_env: owner
250 .as_generic_def_id() 252 .as_generic_def_id()
@@ -334,6 +336,13 @@ impl<'a> InferenceContext<'a> {
334 } 336 }
335 337
336 fn resolve_obligations_as_possible(&mut self) { 338 fn resolve_obligations_as_possible(&mut self) {
339 if self.last_obligations_check == Some(self.table.revision) {
340 // no change
341 return;
342 }
343 let _span = profile::span("resolve_obligations_as_possible");
344
345 self.last_obligations_check = Some(self.table.revision);
337 let obligations = mem::replace(&mut self.obligations, Vec::new()); 346 let obligations = mem::replace(&mut self.obligations, Vec::new());
338 for obligation in obligations { 347 for obligation in obligations {
339 let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone()); 348 let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone());
@@ -360,6 +369,11 @@ impl<'a> InferenceContext<'a> {
360 } 369 }
361 } 370 }
362 371
372 fn push_obligation(&mut self, o: DomainGoal) {
373 self.obligations.push(o);
374 self.last_obligations_check = None;
375 }
376
363 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 377 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
364 self.table.unify(ty1, ty2) 378 self.table.unify(ty1, ty2)
365 } 379 }
@@ -408,8 +422,8 @@ impl<'a> InferenceContext<'a> {
408 }), 422 }),
409 ty: ty.clone(), 423 ty: ty.clone(),
410 }; 424 };
411 self.obligations.push(trait_ref.cast(&Interner)); 425 self.push_obligation(trait_ref.cast(&Interner));
412 self.obligations.push(alias_eq.cast(&Interner)); 426 self.push_obligation(alias_eq.cast(&Interner));
413 self.resolve_ty_as_possible(ty) 427 self.resolve_ty_as_possible(ty)
414 } 428 }
415 None => self.err_ty(), 429 None => self.err_ty(),
@@ -436,7 +450,7 @@ impl<'a> InferenceContext<'a> {
436 let var = self.table.new_type_var(); 450 let var = self.table.new_type_var();
437 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; 451 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
438 let obligation = alias_eq.cast(&Interner); 452 let obligation = alias_eq.cast(&Interner);
439 self.obligations.push(obligation); 453 self.push_obligation(obligation);
440 var 454 var
441 } 455 }
442 456
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 6279aa572..25ab3ea4c 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -99,7 +99,7 @@ impl<'a> InferenceContext<'a> {
99 environment: trait_env, 99 environment: trait_env,
100 }); 100 });
101 if self.db.trait_solve(krate, goal.value).is_some() { 101 if self.db.trait_solve(krate, goal.value).is_some() {
102 self.obligations.push(implements_fn_trait); 102 self.push_obligation(implements_fn_trait);
103 let output_proj_ty = crate::ProjectionTy { 103 let output_proj_ty = crate::ProjectionTy {
104 associated_ty_id: to_assoc_type_id(output_assoc_type), 104 associated_ty_id: to_assoc_type_id(output_assoc_type),
105 substitution: substs, 105 substitution: substs,
@@ -964,7 +964,7 @@ impl<'a> InferenceContext<'a> {
964 let (predicate, binders) = 964 let (predicate, binders) =
965 predicate.clone().subst(parameters).into_value_and_skipped_binders(); 965 predicate.clone().subst(parameters).into_value_and_skipped_binders();
966 always!(binders == 0); // quantified where clauses not yet handled 966 always!(binders == 0); // quantified where clauses not yet handled
967 self.obligations.push(predicate.cast(&Interner)); 967 self.push_obligation(predicate.cast(&Interner));
968 } 968 }
969 // add obligation for trait implementation, if this is a trait method 969 // add obligation for trait implementation, if this is a trait method
970 match def { 970 match def {
@@ -974,7 +974,7 @@ impl<'a> InferenceContext<'a> {
974 // construct a TraitRef 974 // construct a TraitRef
975 let substs = 975 let substs =
976 parameters.prefix(generics(self.db.upcast(), trait_.into()).len()); 976 parameters.prefix(generics(self.db.upcast(), trait_.into()).len());
977 self.obligations.push( 977 self.push_obligation(
978 TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs } 978 TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
979 .cast(&Interner), 979 .cast(&Interner),
980 ); 980 );
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index cefa38509..717738789 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -258,7 +258,7 @@ impl<'a> InferenceContext<'a> {
258 .push(ty.clone()) 258 .push(ty.clone())
259 .fill(std::iter::repeat_with(|| self.table.new_type_var())) 259 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
260 .build(); 260 .build();
261 self.obligations.push( 261 self.push_obligation(
262 TraitRef { 262 TraitRef {
263 trait_id: to_chalk_trait_id(trait_), 263 trait_id: to_chalk_trait_id(trait_),
264 substitution: trait_substs.clone(), 264 substitution: trait_substs.clone(),
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 6e7b0f5a6..5ea4b7481 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -231,6 +231,7 @@ pub(crate) struct TypeVariableData {
231pub(crate) struct InferenceTable { 231pub(crate) struct InferenceTable {
232 pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>, 232 pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>,
233 pub(super) type_variable_table: TypeVariableTable, 233 pub(super) type_variable_table: TypeVariableTable,
234 pub(super) revision: u32,
234} 235}
235 236
236impl InferenceTable { 237impl InferenceTable {
@@ -238,6 +239,7 @@ impl InferenceTable {
238 InferenceTable { 239 InferenceTable {
239 var_unification_table: InPlaceUnificationTable::new(), 240 var_unification_table: InPlaceUnificationTable::new(),
240 type_variable_table: TypeVariableTable { inner: Vec::new() }, 241 type_variable_table: TypeVariableTable { inner: Vec::new() },
242 revision: 0,
241 } 243 }
242 } 244 }
243 245
@@ -360,7 +362,10 @@ impl InferenceTable {
360 == self.type_variable_table.is_diverging(*tv2) => 362 == self.type_variable_table.is_diverging(*tv2) =>
361 { 363 {
362 // both type vars are unknown since we tried to resolve them 364 // both type vars are unknown since we tried to resolve them
363 self.var_unification_table.union(tv1.to_inner(), tv2.to_inner()); 365 if !self.var_unification_table.unioned(tv1.to_inner(), tv2.to_inner()) {
366 self.var_unification_table.union(tv1.to_inner(), tv2.to_inner());
367 self.revision += 1;
368 }
364 true 369 true
365 } 370 }
366 371
@@ -398,6 +403,7 @@ impl InferenceTable {
398 tv.to_inner(), 403 tv.to_inner(),
399 TypeVarValue::Known(other.clone().intern(&Interner)), 404 TypeVarValue::Known(other.clone().intern(&Interner)),
400 ); 405 );
406 self.revision += 1;
401 true 407 true
402 } 408 }
403 409
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 14f34d73c..018621131 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -821,24 +821,38 @@ pub fn associated_type_shorthand_candidates<R>(
821 res: TypeNs, 821 res: TypeNs,
822 mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>, 822 mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
823) -> Option<R> { 823) -> Option<R> {
824 let traits_from_env: Vec<_> = match res { 824 let mut search = |t| {
825 TypeNs::SelfType(impl_id) => match db.impl_trait(impl_id) { 825 for t in all_super_trait_refs(db, t) {
826 None => vec![], 826 let data = db.trait_data(t.hir_trait_id());
827 // FIXME: how to correctly handle higher-ranked bounds here? 827
828 Some(trait_ref) => vec![trait_ref.value.shift_bound_vars_out(DebruijnIndex::ONE)], 828 for (name, assoc_id) in &data.items {
829 }, 829 if let AssocItemId::TypeAliasId(alias) = assoc_id {
830 if let Some(result) = cb(name, &t, *alias) {
831 return Some(result);
832 }
833 }
834 }
835 }
836 None
837 };
838
839 match res {
840 // FIXME: how to correctly handle higher-ranked bounds here?
841 TypeNs::SelfType(impl_id) => {
842 search(db.impl_trait(impl_id)?.value.shift_bound_vars_out(DebruijnIndex::ONE))
843 }
830 TypeNs::GenericParam(param_id) => { 844 TypeNs::GenericParam(param_id) => {
831 let predicates = db.generic_predicates_for_param(param_id); 845 let predicates = db.generic_predicates_for_param(param_id);
832 let mut traits_: Vec<_> = predicates 846 let res = predicates.iter().find_map(|pred| match &pred.value.value {
833 .iter() 847 // FIXME: how to correctly handle higher-ranked bounds here?
834 .filter_map(|pred| match &pred.value.value { 848 WhereClause::Implemented(tr) => {
835 // FIXME: how to correctly handle higher-ranked bounds here? 849 search(tr.clone().shift_bound_vars_out(DebruijnIndex::ONE))
836 WhereClause::Implemented(tr) => { 850 }
837 Some(tr.clone().shift_bound_vars_out(DebruijnIndex::ONE)) 851 _ => None,
838 } 852 });
839 _ => None, 853 if let res @ Some(_) = res {
840 }) 854 return res;
841 .collect(); 855 }
842 // Handle `Self::Type` referring to own associated type in trait definitions 856 // Handle `Self::Type` referring to own associated type in trait definitions
843 if let GenericDefId::TraitId(trait_id) = param_id.parent { 857 if let GenericDefId::TraitId(trait_id) = param_id.parent {
844 let generics = generics(db.upcast(), trait_id.into()); 858 let generics = generics(db.upcast(), trait_id.into());
@@ -849,30 +863,13 @@ pub fn associated_type_shorthand_candidates<R>(
849 trait_id: to_chalk_trait_id(trait_id), 863 trait_id: to_chalk_trait_id(trait_id),
850 substitution: Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST), 864 substitution: Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST),
851 }; 865 };
852 traits_.push(trait_ref); 866 return search(trait_ref);
853 } 867 }
854 } 868 }
855 traits_ 869 None
856 }
857 _ => vec![],
858 };
859
860 for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) {
861 let data = db.trait_data(t.hir_trait_id());
862
863 for (name, assoc_id) in &data.items {
864 match assoc_id {
865 AssocItemId::TypeAliasId(alias) => {
866 if let Some(result) = cb(name, &t, *alias) {
867 return Some(result);
868 }
869 }
870 AssocItemId::FunctionId(_) | AssocItemId::ConstId(_) => {}
871 }
872 } 870 }
871 _ => None,
873 } 872 }
874
875 None
876} 873}
877 874
878/// Build the type of all specific fields of a struct or enum variant. 875/// Build the type of all specific fields of a struct or enum variant.
diff --git a/docs/dev/style.md b/docs/dev/style.md
index e4a1672ca..c594946be 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -55,9 +55,9 @@ https://www.tedinski.com/2018/02/06/system-boundaries.html
55We try to be very conservative with usage of crates.io dependencies. 55We try to be very conservative with usage of crates.io dependencies.
56Don't use small "helper" crates (exception: `itertools` is allowed). 56Don't use small "helper" crates (exception: `itertools` is allowed).
57If there's some general reusable bit of code you need, consider adding it to the `stdx` crate. 57If there's some general reusable bit of code you need, consider adding it to the `stdx` crate.
58A useful exercise is to read Cargo.lock and see if some of the *transitive* dependencies do not make sense for rust-analyzer.
58 59
59**Rationale:** keep compile times low, create ecosystem pressure for faster 60**Rationale:** keep compile times low, create ecosystem pressure for faster compiles, reduce the number of things which might break.
60compiles, reduce the number of things which might break.
61 61
62## Commit Style 62## Commit Style
63 63
@@ -806,9 +806,48 @@ if let Some(expected_type) = ctx.expected_type.as_ref() {
806} 806}
807``` 807```
808 808
809**Rational:** `match` is almost always more compact. 809**Rationale:** `match` is almost always more compact.
810The `else` branch can get a more precise pattern: `None` or `Err(_)` instead of `_`. 810The `else` branch can get a more precise pattern: `None` or `Err(_)` instead of `_`.
811 811
812## Helper Functions
813
814Avoid creating singe-use helper functions:
815
816```rust
817// GOOD
818let buf = {
819 let mut buf = get_empty_buf(&mut arena);
820 buf.add_item(item);
821 buf
822};
823
824// BAD
825
826let buf = prepare_buf(&mut arena, item);
827
828...
829
830fn prepare_buf(arena: &mut Arena, item: Item) -> ItemBuf {
831 let mut res = get_empty_buf(&mut arena);
832 res.add_item(item);
833 res
834}
835```
836
837Exception: if you want to make use of `return` or `?`.
838
839**Rationale:** single-use functions change frequently, adding or removing parameters adds churn.
840A block serves just as well to delineate a bit of logic, but has access to all the context.
841Re-using originally single-purpose function often leads to bad coupling.
842
843## Helper Variables
844
845Introduce helper variables freely, especially for multiline conditions.
846
847**Rationale:** like blocks, single-use variables are a cognitively cheap abstraction, as they have access to all the context.
848Extra variables help during debugging, they make it easy to print/view important intermediate results.
849Giving a name to a condition in `if` expression often improves clarity and leads to a nicer formatted code.
850
812## Token names 851## Token names
813 852
814Use `T![foo]` instead of `SyntaxKind::FOO_KW`. 853Use `T![foo]` instead of `SyntaxKind::FOO_KW`.