Skip to content

Commit 342fd2b

Browse files
committed
fix: Properly handle local trait impls
1 parent 284c174 commit 342fd2b

File tree

13 files changed

+138
-95
lines changed

13 files changed

+138
-95
lines changed

crates/hir-def/src/db.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
9393
///
9494
/// The `block_def_map` for block 0 would return `None`, while `block_def_map` of block 1 would
9595
/// return a `DefMap` containing `inner`.
96+
// FIXME: This actually can't return None anymore as we no longer allocate block scopes for
97+
// non item declaring blocks
9698
#[salsa::invoke(DefMap::block_def_map_query)]
9799
fn block_def_map(&self, block: BlockId) -> Option<Arc<DefMap>>;
98100

crates/hir-ty/src/chalk_db.rs

Lines changed: 35 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
//! The implementation of `RustIrDatabase` for Chalk, which provides information
22
//! about the code that Chalk needs.
3-
use std::sync::Arc;
3+
use std::{iter, sync::Arc};
44

5-
use cov_mark::hit;
65
use tracing::debug;
76

87
use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
@@ -12,17 +11,16 @@ use base_db::CrateId;
1211
use hir_def::{
1312
expr::Movability,
1413
lang_item::{lang_attr, LangItem, LangItemTarget},
15-
AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
14+
AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId,
1615
};
1716
use hir_expand::name::name;
1817

1918
use crate::{
2019
db::HirDatabase,
2120
display::HirDisplay,
22-
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders,
23-
make_single_type_binders,
21+
from_assoc_type_id, from_chalk_trait_id, make_binders, make_single_type_binders,
2422
mapping::{from_chalk, ToChalk, TypeAliasAsValue},
25-
method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
23+
method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
2624
to_assoc_type_id, to_chalk_trait_id,
2725
traits::ChalkContext,
2826
utils::generics,
@@ -108,53 +106,41 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
108106
_ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
109107
};
110108

111-
fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> {
112-
let block = module.containing_block()?;
113-
hit!(block_local_impls);
114-
db.trait_impls_in_block(block)
115-
}
116-
117109
// Note: Since we're using impls_for_trait, only impls where the trait
118110
// can be resolved should ever reach Chalk. impl_datum relies on that
119111
// and will panic if the trait can't be resolved.
120112
let in_deps = self.db.trait_impls_in_deps(self.krate);
121113
let in_self = self.db.trait_impls_in_crate(self.krate);
122-
let trait_module = trait_.module(self.db.upcast());
123-
let type_module = match self_ty_fp {
124-
Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
125-
Some(TyFingerprint::ForeignType(type_id)) => {
126-
Some(from_foreign_def_id(type_id).module(self.db.upcast()))
127-
}
128-
Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
129-
_ => None,
130-
};
131-
let impl_maps = [
132-
Some(in_deps),
133-
Some(in_self),
134-
local_impls(self.db, trait_module),
135-
type_module.and_then(|m| local_impls(self.db, m)),
136-
];
137114

138-
let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
115+
let impl_maps = [in_deps, in_self];
116+
let block_impls = iter::successors(self.block, |&block_id| {
117+
cov_mark::hit!(block_local_impls);
118+
self.db
119+
.block_def_map(block_id)
120+
.and_then(|map| map.parent())
121+
.and_then(|module| module.containing_block())
122+
})
123+
.filter_map(|block_id| self.db.trait_impls_in_block(block_id));
139124

140-
let result: Vec<_> = if fps.is_empty() {
141-
debug!("Unrestricted search for {:?} impls...", trait_);
142-
impl_maps
143-
.iter()
144-
.filter_map(|o| o.as_ref())
145-
.flat_map(|impls| impls.for_trait(trait_).map(id_to_chalk))
146-
.collect()
147-
} else {
148-
impl_maps
149-
.iter()
150-
.filter_map(|o| o.as_ref())
151-
.flat_map(|impls| {
152-
fps.iter().flat_map(move |fp| {
153-
impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
154-
})
155-
})
156-
.collect()
157-
};
125+
let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
126+
let mut result = vec![];
127+
match fps {
128+
[] => {
129+
debug!("Unrestricted search for {:?} impls...", trait_);
130+
impl_maps.into_iter().chain(block_impls).for_each(|impls| {
131+
result.extend(impls.for_trait(trait_).map(id_to_chalk));
132+
});
133+
}
134+
fps => {
135+
impl_maps.into_iter().chain(block_impls).for_each(|impls| {
136+
result.extend(
137+
fps.iter().flat_map(|fp| {
138+
impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
139+
}),
140+
);
141+
});
142+
}
143+
}
158144

159145
debug!("impls_for_trait returned {} impls", result.len());
160146
result
@@ -193,7 +179,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
193179
&self,
194180
environment: &chalk_ir::Environment<Interner>,
195181
) -> chalk_ir::ProgramClauses<Interner> {
196-
self.db.program_clauses_for_chalk_env(self.krate, environment.clone())
182+
self.db.program_clauses_for_chalk_env(self.krate, self.block, environment.clone())
197183
}
198184

199185
fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> {
@@ -451,9 +437,10 @@ impl<'a> chalk_ir::UnificationDatabase<Interner> for &'a dyn HirDatabase {
451437
pub(crate) fn program_clauses_for_chalk_env_query(
452438
db: &dyn HirDatabase,
453439
krate: CrateId,
440+
block: Option<BlockId>,
454441
environment: chalk_ir::Environment<Interner>,
455442
) -> chalk_ir::ProgramClauses<Interner> {
456-
chalk_solve::program_clauses_for_env(&ChalkContext { db, krate }, &environment)
443+
chalk_solve::program_clauses_for_env(&ChalkContext { db, krate, block }, &environment)
457444
}
458445

459446
pub(crate) fn associated_ty_data_query(

crates/hir-ty/src/db.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
129129
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
130130

131131
#[salsa::invoke(TraitImpls::trait_impls_in_block_query)]
132-
fn trait_impls_in_block(&self, krate: BlockId) -> Option<Arc<TraitImpls>>;
132+
fn trait_impls_in_block(&self, block: BlockId) -> Option<Arc<TraitImpls>>;
133133

134134
#[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
135135
fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
@@ -197,20 +197,23 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
197197
fn trait_solve(
198198
&self,
199199
krate: CrateId,
200+
block: Option<BlockId>,
200201
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
201202
) -> Option<crate::Solution>;
202203

203204
#[salsa::invoke(crate::traits::trait_solve_query)]
204205
fn trait_solve_query(
205206
&self,
206207
krate: CrateId,
208+
block: Option<BlockId>,
207209
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
208210
) -> Option<crate::Solution>;
209211

210212
#[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)]
211213
fn program_clauses_for_chalk_env(
212214
&self,
213215
krate: CrateId,
216+
block: Option<BlockId>,
214217
env: chalk_ir::Environment<Interner>,
215218
) -> chalk_ir::ProgramClauses<Interner>;
216219
}
@@ -232,10 +235,11 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
232235
fn trait_solve_wait(
233236
db: &dyn HirDatabase,
234237
krate: CrateId,
238+
block: Option<BlockId>,
235239
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
236240
) -> Option<crate::Solution> {
237241
let _p = profile::span("trait_solve::wait");
238-
db.trait_solve_query(krate, goal)
242+
db.trait_solve_query(krate, block, goal)
239243
}
240244

241245
#[test]

crates/hir-ty/src/infer.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use crate::{
4040
db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
4141
lower::ImplTraitLoweringMode, static_lifetime, to_assoc_type_id, AliasEq, AliasTy, Const,
4242
DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId,
43-
Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
43+
Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
4444
};
4545

4646
// This lint has a false positive here. See the link below for details.
@@ -442,7 +442,6 @@ pub(crate) struct InferenceContext<'a> {
442442
pub(crate) body: &'a Body,
443443
pub(crate) resolver: Resolver,
444444
table: unify::InferenceTable<'a>,
445-
trait_env: Arc<TraitEnvironment>,
446445
/// The traits in scope, disregarding block modules. This is used for caching purposes.
447446
traits_in_scope: FxHashSet<TraitId>,
448447
pub(crate) result: InferenceResult,
@@ -516,8 +515,7 @@ impl<'a> InferenceContext<'a> {
516515
let trait_env = db.trait_environment_for_body(owner);
517516
InferenceContext {
518517
result: InferenceResult::default(),
519-
table: unify::InferenceTable::new(db, trait_env.clone()),
520-
trait_env,
518+
table: unify::InferenceTable::new(db, trait_env),
521519
return_ty: TyKind::Error.intern(Interner), // set in collect_* calls
522520
resume_yield_tys: None,
523521
return_coercion: None,

crates/hir-ty/src/infer/coerce.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ impl<'a> InferenceTable<'a> {
636636
// Need to find out in what cases this is necessary
637637
let solution = self
638638
.db
639-
.trait_solve(krate, canonicalized.value.clone().cast(Interner))
639+
.trait_solve(krate, self.trait_env.block, canonicalized.value.clone().cast(Interner))
640640
.ok_or(TypeError)?;
641641

642642
match solution {

crates/hir-ty/src/infer/expr.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::{
44
iter::{repeat, repeat_with},
55
mem,
6+
sync::Arc,
67
};
78

89
use chalk_ir::{
@@ -15,7 +16,7 @@ use hir_def::{
1516
generics::TypeOrConstParamData,
1617
lang_item::LangItem,
1718
path::{GenericArg, GenericArgs},
18-
ConstParamId, FieldId, ItemContainerId, Lookup,
19+
BlockId, ConstParamId, FieldId, ItemContainerId, Lookup,
1920
};
2021
use hir_expand::name::{name, Name};
2122
use stdx::always;
@@ -147,19 +148,19 @@ impl<'a> InferenceContext<'a> {
147148
self.infer_top_pat(pat, &input_ty);
148149
self.result.standard_types.bool_.clone()
149150
}
150-
Expr::Block { statements, tail, label, id: _ } => {
151-
self.infer_block(tgt_expr, statements, *tail, *label, expected)
151+
Expr::Block { statements, tail, label, id } => {
152+
self.infer_block(tgt_expr, *id, statements, *tail, *label, expected)
152153
}
153-
Expr::Unsafe { id: _, statements, tail } => {
154-
self.infer_block(tgt_expr, statements, *tail, None, expected)
154+
Expr::Unsafe { id, statements, tail } => {
155+
self.infer_block(tgt_expr, *id, statements, *tail, None, expected)
155156
}
156-
Expr::Const { id: _, statements, tail } => {
157+
Expr::Const { id, statements, tail } => {
157158
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
158-
this.infer_block(tgt_expr, statements, *tail, None, expected)
159+
this.infer_block(tgt_expr, *id, statements, *tail, None, expected)
159160
})
160161
.1
161162
}
162-
Expr::Async { id: _, statements, tail } => {
163+
Expr::Async { id, statements, tail } => {
163164
let ret_ty = self.table.new_type_var();
164165
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
165166
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
@@ -170,6 +171,7 @@ impl<'a> InferenceContext<'a> {
170171
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
171172
this.infer_block(
172173
tgt_expr,
174+
*id,
173175
statements,
174176
*tail,
175177
None,
@@ -394,7 +396,7 @@ impl<'a> InferenceContext<'a> {
394396
}
395397
}
396398
let trait_ = fn_x
397-
.get_id(self.db, self.trait_env.krate)
399+
.get_id(self.db, self.table.trait_env.krate)
398400
.expect("We just used it");
399401
let trait_data = self.db.trait_data(trait_);
400402
if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) {
@@ -787,7 +789,7 @@ impl<'a> InferenceContext<'a> {
787789
let canonicalized = self.canonicalize(base_ty.clone());
788790
let receiver_adjustments = method_resolution::resolve_indexing_op(
789791
self.db,
790-
self.trait_env.clone(),
792+
self.table.trait_env.clone(),
791793
canonicalized.value,
792794
index_trait,
793795
);
@@ -1205,13 +1207,19 @@ impl<'a> InferenceContext<'a> {
12051207
fn infer_block(
12061208
&mut self,
12071209
expr: ExprId,
1210+
block_id: Option<BlockId>,
12081211
statements: &[Statement],
12091212
tail: Option<ExprId>,
12101213
label: Option<LabelId>,
12111214
expected: &Expectation,
12121215
) -> Ty {
12131216
let coerce_ty = expected.coercion_target_type(&mut self.table);
12141217
let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr);
1218+
let prev_env = block_id.map(|block_id| {
1219+
let prev_env = self.table.trait_env.clone();
1220+
Arc::make_mut(&mut self.table.trait_env).block = Some(block_id);
1221+
prev_env
1222+
});
12151223

12161224
let (break_ty, ty) =
12171225
self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty.clone()), label, |this| {
@@ -1300,6 +1308,9 @@ impl<'a> InferenceContext<'a> {
13001308
}
13011309
});
13021310
self.resolver.reset_to_guard(g);
1311+
if let Some(prev_env) = prev_env {
1312+
self.table.trait_env = prev_env;
1313+
}
13031314

13041315
break_ty.unwrap_or(ty)
13051316
}
@@ -1398,7 +1409,7 @@ impl<'a> InferenceContext<'a> {
13981409
method_resolution::lookup_method(
13991410
self.db,
14001411
&canonicalized_receiver.value,
1401-
self.trait_env.clone(),
1412+
self.table.trait_env.clone(),
14021413
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
14031414
VisibleFromModule::Filter(self.resolver.module()),
14041415
name,
@@ -1431,7 +1442,7 @@ impl<'a> InferenceContext<'a> {
14311442
let resolved = method_resolution::lookup_method(
14321443
self.db,
14331444
&canonicalized_receiver.value,
1434-
self.trait_env.clone(),
1445+
self.table.trait_env.clone(),
14351446
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
14361447
VisibleFromModule::Filter(self.resolver.module()),
14371448
method_name,

crates/hir-ty/src/infer/unify.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,8 @@ impl<'a> InferenceTable<'a> {
462462
pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option<Solution> {
463463
let in_env = InEnvironment::new(&self.trait_env.env, goal);
464464
let canonicalized = self.canonicalize(in_env);
465-
let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value);
465+
let solution =
466+
self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized.value);
466467
solution
467468
}
468469

@@ -597,7 +598,11 @@ impl<'a> InferenceTable<'a> {
597598
&mut self,
598599
canonicalized: &Canonicalized<InEnvironment<Goal>>,
599600
) -> bool {
600-
let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value.clone());
601+
let solution = self.db.trait_solve(
602+
self.trait_env.krate,
603+
self.trait_env.block,
604+
canonicalized.value.clone(),
605+
);
601606

602607
match solution {
603608
Some(Solution::Unique(canonical_subst)) => {
@@ -684,7 +689,11 @@ impl<'a> InferenceTable<'a> {
684689
environment: trait_env.clone(),
685690
};
686691
let canonical = self.canonicalize(obligation.clone());
687-
if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
692+
if self
693+
.db
694+
.trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner))
695+
.is_some()
696+
{
688697
self.register_obligation(obligation.goal);
689698
let return_ty = self.normalize_projection_ty(projection);
690699
for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
@@ -695,7 +704,11 @@ impl<'a> InferenceTable<'a> {
695704
environment: trait_env.clone(),
696705
};
697706
let canonical = self.canonicalize(obligation.clone());
698-
if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
707+
if self
708+
.db
709+
.trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner))
710+
.is_some()
711+
{
699712
return Some((fn_x, arg_tys, return_ty));
700713
}
701714
}

crates/hir-ty/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! The type system. We currently use this to infer types for completion, hover
22
//! information and various assists.
3-
43
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
54

65
#[allow(unused)]

0 commit comments

Comments
 (0)