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.
This commit is contained in:
bors 2023-03-28 06:36:35 +00:00
commit f73510560f
13 changed files with 138 additions and 95 deletions

View File

@ -93,6 +93,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
///
/// The `block_def_map` for block 0 would return `None`, while `block_def_map` of block 1 would
/// return a `DefMap` containing `inner`.
// FIXME: This actually can't return None anymore as we no longer allocate block scopes for
// non item declaring blocks
#[salsa::invoke(DefMap::block_def_map_query)]
fn block_def_map(&self, block: BlockId) -> Option<Arc<DefMap>>;

View File

@ -1,8 +1,7 @@
//! The implementation of `RustIrDatabase` for Chalk, which provides information
//! about the code that Chalk needs.
use std::sync::Arc;
use std::{iter, sync::Arc};
use cov_mark::hit;
use tracing::debug;
use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
@ -12,17 +11,16 @@ use base_db::CrateId;
use hir_def::{
expr::Movability,
lang_item::{lang_attr, LangItem, LangItemTarget},
AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId,
};
use hir_expand::name::name;
use crate::{
db::HirDatabase,
display::HirDisplay,
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders,
make_single_type_binders,
from_assoc_type_id, from_chalk_trait_id, make_binders, make_single_type_binders,
mapping::{from_chalk, ToChalk, TypeAliasAsValue},
method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
to_assoc_type_id, to_chalk_trait_id,
traits::ChalkContext,
utils::generics,
@ -108,53 +106,41 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
_ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
};
fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> {
let block = module.containing_block()?;
hit!(block_local_impls);
db.trait_impls_in_block(block)
}
// Note: Since we're using impls_for_trait, only impls where the trait
// can be resolved should ever reach Chalk. impl_datum relies on that
// and will panic if the trait can't be resolved.
let in_deps = self.db.trait_impls_in_deps(self.krate);
let in_self = self.db.trait_impls_in_crate(self.krate);
let trait_module = trait_.module(self.db.upcast());
let type_module = match self_ty_fp {
Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
Some(TyFingerprint::ForeignType(type_id)) => {
Some(from_foreign_def_id(type_id).module(self.db.upcast()))
}
Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
_ => None,
};
let impl_maps = [
Some(in_deps),
Some(in_self),
local_impls(self.db, trait_module),
type_module.and_then(|m| local_impls(self.db, m)),
];
let impl_maps = [in_deps, in_self];
let block_impls = iter::successors(self.block, |&block_id| {
cov_mark::hit!(block_local_impls);
self.db
.block_def_map(block_id)
.and_then(|map| map.parent())
.and_then(|module| module.containing_block())
})
.filter_map(|block_id| self.db.trait_impls_in_block(block_id));
let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
let result: Vec<_> = if fps.is_empty() {
debug!("Unrestricted search for {:?} impls...", trait_);
impl_maps
.iter()
.filter_map(|o| o.as_ref())
.flat_map(|impls| impls.for_trait(trait_).map(id_to_chalk))
.collect()
} else {
impl_maps
.iter()
.filter_map(|o| o.as_ref())
.flat_map(|impls| {
fps.iter().flat_map(move |fp| {
impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
})
})
.collect()
};
let mut result = vec![];
match fps {
[] => {
debug!("Unrestricted search for {:?} impls...", trait_);
impl_maps.into_iter().chain(block_impls).for_each(|impls| {
result.extend(impls.for_trait(trait_).map(id_to_chalk));
});
}
fps => {
impl_maps.into_iter().chain(block_impls).for_each(|impls| {
result.extend(
fps.iter().flat_map(|fp| {
impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
}),
);
});
}
}
debug!("impls_for_trait returned {} impls", result.len());
result
@ -193,7 +179,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
&self,
environment: &chalk_ir::Environment<Interner>,
) -> chalk_ir::ProgramClauses<Interner> {
self.db.program_clauses_for_chalk_env(self.krate, environment.clone())
self.db.program_clauses_for_chalk_env(self.krate, self.block, environment.clone())
}
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 {
pub(crate) fn program_clauses_for_chalk_env_query(
db: &dyn HirDatabase,
krate: CrateId,
block: Option<BlockId>,
environment: chalk_ir::Environment<Interner>,
) -> chalk_ir::ProgramClauses<Interner> {
chalk_solve::program_clauses_for_env(&ChalkContext { db, krate }, &environment)
chalk_solve::program_clauses_for_env(&ChalkContext { db, krate, block }, &environment)
}
pub(crate) fn associated_ty_data_query(

View File

@ -129,7 +129,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
#[salsa::invoke(TraitImpls::trait_impls_in_block_query)]
fn trait_impls_in_block(&self, krate: BlockId) -> Option<Arc<TraitImpls>>;
fn trait_impls_in_block(&self, block: BlockId) -> Option<Arc<TraitImpls>>;
#[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
@ -197,6 +197,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn trait_solve(
&self,
krate: CrateId,
block: Option<BlockId>,
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
) -> Option<crate::Solution>;
@ -204,6 +205,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn trait_solve_query(
&self,
krate: CrateId,
block: Option<BlockId>,
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
) -> Option<crate::Solution>;
@ -211,6 +213,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn program_clauses_for_chalk_env(
&self,
krate: CrateId,
block: Option<BlockId>,
env: chalk_ir::Environment<Interner>,
) -> chalk_ir::ProgramClauses<Interner>;
}
@ -232,10 +235,11 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
fn trait_solve_wait(
db: &dyn HirDatabase,
krate: CrateId,
block: Option<BlockId>,
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
) -> Option<crate::Solution> {
let _p = profile::span("trait_solve::wait");
db.trait_solve_query(krate, goal)
db.trait_solve_query(krate, block, goal)
}
#[test]

View File

@ -40,7 +40,7 @@ use crate::{
db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
lower::ImplTraitLoweringMode, static_lifetime, to_assoc_type_id, AliasEq, AliasTy, Const,
DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId,
Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
};
// This lint has a false positive here. See the link below for details.
@ -442,7 +442,6 @@ pub(crate) struct InferenceContext<'a> {
pub(crate) body: &'a Body,
pub(crate) resolver: Resolver,
table: unify::InferenceTable<'a>,
trait_env: Arc<TraitEnvironment>,
/// The traits in scope, disregarding block modules. This is used for caching purposes.
traits_in_scope: FxHashSet<TraitId>,
pub(crate) result: InferenceResult,
@ -516,8 +515,7 @@ impl<'a> InferenceContext<'a> {
let trait_env = db.trait_environment_for_body(owner);
InferenceContext {
result: InferenceResult::default(),
table: unify::InferenceTable::new(db, trait_env.clone()),
trait_env,
table: unify::InferenceTable::new(db, trait_env),
return_ty: TyKind::Error.intern(Interner), // set in collect_* calls
resume_yield_tys: None,
return_coercion: None,

View File

@ -636,7 +636,7 @@ impl<'a> InferenceTable<'a> {
// Need to find out in what cases this is necessary
let solution = self
.db
.trait_solve(krate, canonicalized.value.clone().cast(Interner))
.trait_solve(krate, self.trait_env.block, canonicalized.value.clone().cast(Interner))
.ok_or(TypeError)?;
match solution {

View File

@ -3,6 +3,7 @@
use std::{
iter::{repeat, repeat_with},
mem,
sync::Arc,
};
use chalk_ir::{
@ -15,7 +16,7 @@ use hir_def::{
generics::TypeOrConstParamData,
lang_item::LangItem,
path::{GenericArg, GenericArgs},
ConstParamId, FieldId, ItemContainerId, Lookup,
BlockId, ConstParamId, FieldId, ItemContainerId, Lookup,
};
use hir_expand::name::{name, Name};
use stdx::always;
@ -147,19 +148,19 @@ impl<'a> InferenceContext<'a> {
self.infer_top_pat(pat, &input_ty);
self.result.standard_types.bool_.clone()
}
Expr::Block { statements, tail, label, id: _ } => {
self.infer_block(tgt_expr, statements, *tail, *label, expected)
Expr::Block { statements, tail, label, id } => {
self.infer_block(tgt_expr, *id, statements, *tail, *label, expected)
}
Expr::Unsafe { id: _, statements, tail } => {
self.infer_block(tgt_expr, statements, *tail, None, expected)
Expr::Unsafe { id, statements, tail } => {
self.infer_block(tgt_expr, *id, statements, *tail, None, expected)
}
Expr::Const { id: _, statements, tail } => {
Expr::Const { id, statements, tail } => {
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
this.infer_block(tgt_expr, statements, *tail, None, expected)
this.infer_block(tgt_expr, *id, statements, *tail, None, expected)
})
.1
}
Expr::Async { id: _, statements, tail } => {
Expr::Async { id, statements, tail } => {
let ret_ty = self.table.new_type_var();
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
@ -170,6 +171,7 @@ impl<'a> InferenceContext<'a> {
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
this.infer_block(
tgt_expr,
*id,
statements,
*tail,
None,
@ -394,7 +396,7 @@ impl<'a> InferenceContext<'a> {
}
}
let trait_ = fn_x
.get_id(self.db, self.trait_env.krate)
.get_id(self.db, self.table.trait_env.krate)
.expect("We just used it");
let trait_data = self.db.trait_data(trait_);
if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) {
@ -787,7 +789,7 @@ impl<'a> InferenceContext<'a> {
let canonicalized = self.canonicalize(base_ty.clone());
let receiver_adjustments = method_resolution::resolve_indexing_op(
self.db,
self.trait_env.clone(),
self.table.trait_env.clone(),
canonicalized.value,
index_trait,
);
@ -1205,6 +1207,7 @@ impl<'a> InferenceContext<'a> {
fn infer_block(
&mut self,
expr: ExprId,
block_id: Option<BlockId>,
statements: &[Statement],
tail: Option<ExprId>,
label: Option<LabelId>,
@ -1212,6 +1215,11 @@ impl<'a> InferenceContext<'a> {
) -> Ty {
let coerce_ty = expected.coercion_target_type(&mut self.table);
let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr);
let prev_env = block_id.map(|block_id| {
let prev_env = self.table.trait_env.clone();
Arc::make_mut(&mut self.table.trait_env).block = Some(block_id);
prev_env
});
let (break_ty, ty) =
self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty.clone()), label, |this| {
@ -1300,6 +1308,9 @@ impl<'a> InferenceContext<'a> {
}
});
self.resolver.reset_to_guard(g);
if let Some(prev_env) = prev_env {
self.table.trait_env = prev_env;
}
break_ty.unwrap_or(ty)
}
@ -1398,7 +1409,7 @@ impl<'a> InferenceContext<'a> {
method_resolution::lookup_method(
self.db,
&canonicalized_receiver.value,
self.trait_env.clone(),
self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()),
name,
@ -1431,7 +1442,7 @@ impl<'a> InferenceContext<'a> {
let resolved = method_resolution::lookup_method(
self.db,
&canonicalized_receiver.value,
self.trait_env.clone(),
self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()),
method_name,

View File

@ -462,7 +462,8 @@ impl<'a> InferenceTable<'a> {
pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option<Solution> {
let in_env = InEnvironment::new(&self.trait_env.env, goal);
let canonicalized = self.canonicalize(in_env);
let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value);
let solution =
self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized.value);
solution
}
@ -597,7 +598,11 @@ impl<'a> InferenceTable<'a> {
&mut self,
canonicalized: &Canonicalized<InEnvironment<Goal>>,
) -> bool {
let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value.clone());
let solution = self.db.trait_solve(
self.trait_env.krate,
self.trait_env.block,
canonicalized.value.clone(),
);
match solution {
Some(Solution::Unique(canonical_subst)) => {
@ -684,7 +689,11 @@ impl<'a> InferenceTable<'a> {
environment: trait_env.clone(),
};
let canonical = self.canonicalize(obligation.clone());
if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
if self
.db
.trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner))
.is_some()
{
self.register_obligation(obligation.goal);
let return_ty = self.normalize_projection_ty(projection);
for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
@ -695,7 +704,11 @@ impl<'a> InferenceTable<'a> {
environment: trait_env.clone(),
};
let canonical = self.canonicalize(obligation.clone());
if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
if self
.db
.trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner))
.is_some()
{
return Some((fn_x, arg_tys, return_ty));
}
}

View File

@ -1,6 +1,5 @@
//! The type system. We currently use this to infer types for completion, hover
//! information and various assists.
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
#[allow(unused)]

View File

@ -1507,7 +1507,7 @@ pub(crate) fn trait_environment_query(
let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses);
Arc::new(TraitEnvironment { krate, traits_from_clauses: traits_in_scope, env })
Arc::new(TraitEnvironment { krate, block: None, traits_from_clauses: traits_in_scope, env })
}
/// Resolve the where clause(s) of an item with generics.

View File

@ -271,6 +271,7 @@ pub struct InherentImpls {
impl InherentImpls {
pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
let _p = profile::span("inherent_impls_in_crate_query").detail(|| format!("{krate:?}"));
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
let crate_def_map = db.crate_def_map(krate);
@ -284,13 +285,14 @@ impl InherentImpls {
db: &dyn HirDatabase,
block: BlockId,
) -> Option<Arc<Self>> {
let _p = profile::span("inherent_impls_in_block_query");
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
if let Some(block_def_map) = db.block_def_map(block) {
impls.collect_def_map(db, &block_def_map);
impls.shrink_to_fit();
return Some(Arc::new(impls));
}
None
let block_def_map = db.block_def_map(block)?;
impls.collect_def_map(db, &block_def_map);
impls.shrink_to_fit();
Some(Arc::new(impls))
}
fn shrink_to_fit(&mut self) {
@ -1140,7 +1142,7 @@ fn iterate_trait_method_candidates(
};
if !known_implemented {
let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty);
if db.trait_solve(env.krate, goal.cast(Interner)).is_none() {
if db.trait_solve(env.krate, env.block, goal.cast(Interner)).is_none() {
continue 'traits;
}
}
@ -1317,7 +1319,7 @@ pub fn resolve_indexing_op(
let deref_chain = autoderef_method_receiver(&mut table, ty);
for (ty, adj) in deref_chain {
let goal = generic_implements_goal(db, env.clone(), index_trait, &ty);
if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
if db.trait_solve(env.krate, env.block, goal.cast(Interner)).is_some() {
return Some(adj);
}
}
@ -1342,14 +1344,12 @@ fn is_valid_candidate(
) -> IsValidCandidate {
let db = table.db;
match item {
AssocItemId::FunctionId(m) => {
is_valid_fn_candidate(table, m, name, receiver_ty, self_ty, visible_from_module)
AssocItemId::FunctionId(f) => {
is_valid_fn_candidate(table, f, name, receiver_ty, self_ty, visible_from_module)
}
AssocItemId::ConstId(c) => {
let data = db.const_data(c);
check_that!(receiver_ty.is_none());
check_that!(name.map_or(true, |n| data.name.as_ref() == Some(n)));
check_that!(name.map_or(true, |n| db.const_data(c).name.as_ref() == Some(n)));
if let Some(from_module) = visible_from_module {
if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) {
@ -1473,7 +1473,7 @@ pub fn implements_trait(
trait_: TraitId,
) -> bool {
let goal = generic_implements_goal(db, env.clone(), trait_, ty);
let solution = db.trait_solve(env.krate, goal.cast(Interner));
let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
solution.is_some()
}
@ -1485,7 +1485,7 @@ pub fn implements_trait_unique(
trait_: TraitId,
) -> bool {
let goal = generic_implements_goal(db, env.clone(), trait_, ty);
let solution = db.trait_solve(env.krate, goal.cast(Interner));
let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
matches!(solution, Some(crate::Solution::Unique(_)))
}

View File

@ -3717,7 +3717,6 @@ async fn get_accounts() -> Result<u32, ()> {
#[test]
fn local_impl_1() {
check!(block_local_impls);
check_types(
r#"
trait Trait<T> {
@ -3739,7 +3738,6 @@ fn test() {
#[test]
fn local_impl_2() {
check!(block_local_impls);
check_types(
r#"
struct S;
@ -3761,7 +3759,6 @@ fn test() {
#[test]
fn local_impl_3() {
check!(block_local_impls);
check_types(
r#"
trait Trait<T> {
@ -3785,6 +3782,33 @@ fn test() {
);
}
#[test]
fn foreign_trait_with_local_trait_impl() {
check!(block_local_impls);
check(
r#"
mod module {
pub trait T {
const C: usize;
fn f(&self);
}
}
fn f() {
use module::T;
impl T for usize {
const C: usize = 0;
fn f(&self) {}
}
0usize.f();
//^^^^^^^^^^ type: ()
usize::C;
//^^^^^^^^type: usize
}
"#,
);
}
#[test]
fn associated_type_sized_bounds() {
check_infer(

View File

@ -9,7 +9,7 @@ use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
use base_db::CrateId;
use hir_def::{
lang_item::{LangItem, LangItemTarget},
TraitId,
BlockId, TraitId,
};
use hir_expand::name::{name, Name};
use stdx::panic_context;
@ -27,6 +27,7 @@ const CHALK_SOLVER_FUEL: i32 = 1000;
pub(crate) struct ChalkContext<'a> {
pub(crate) db: &'a dyn HirDatabase,
pub(crate) krate: CrateId,
pub(crate) block: Option<BlockId>,
}
fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
@ -44,6 +45,7 @@ fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitEnvironment {
pub krate: CrateId,
pub block: Option<BlockId>,
// FIXME make this a BTreeMap
pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
pub env: chalk_ir::Environment<Interner>,
@ -53,6 +55,7 @@ impl TraitEnvironment {
pub fn empty(krate: CrateId) -> Self {
TraitEnvironment {
krate,
block: None,
traits_from_clauses: Vec::new(),
env: chalk_ir::Environment::new(Interner),
}
@ -79,6 +82,7 @@ pub(crate) fn normalize_projection_query(
pub(crate) fn trait_solve_query(
db: &dyn HirDatabase,
krate: CrateId,
block: Option<BlockId>,
goal: Canonical<InEnvironment<Goal>>,
) -> Option<Solution> {
let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) {
@ -104,15 +108,16 @@ pub(crate) fn trait_solve_query(
// We currently don't deal with universes (I think / hope they're not yet
// relevant for our use cases?)
let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
solve(db, krate, &u_canonical)
solve(db, krate, block, &u_canonical)
}
fn solve(
db: &dyn HirDatabase,
krate: CrateId,
block: Option<BlockId>,
goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
) -> Option<chalk_solve::Solution<Interner>> {
let context = ChalkContext { db, krate };
let context = ChalkContext { db, krate, block };
tracing::debug!("solve goal: {:?}", goal);
let mut solver = create_chalk_solver();

View File

@ -3331,7 +3331,7 @@ impl Type {
binders: CanonicalVarKinds::empty(Interner),
};
db.trait_solve(self.env.krate, goal).is_some()
db.trait_solve(self.env.krate, self.env.block, goal).is_some()
}
pub fn normalize_trait_assoc_type(