Skip to content

Commit f735105

Browse files
committed
Auto merge of #14424 - Veykril:local-trait-impls, r=Veykril
fix: Properly handle local trait impls Before we only handled trait impls that came from the block of either the trait or the target type, we now handle them correctly by tracking the block we are currently inferring from, then walking that up to collect all block trait impls.
2 parents a869ca3 + 342fd2b commit f735105

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)