Cleanup term search related changes

This commit is contained in:
Tavo Annus 2024-02-01 11:02:19 +02:00
parent 88964c0b6a
commit 125791386d
26 changed files with 590 additions and 516 deletions

View file

@ -1085,6 +1085,7 @@ impl Field {
Type::new(db, var_id, ty)
}
// FIXME: Find better API to also handle const generics
pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
let var_id = self.parent.into();
let def_id: AdtId = match self.parent {
@ -1094,12 +1095,11 @@ impl Field {
};
let mut generics = generics.map(|it| it.ty.clone());
let substs = TyBuilder::subst_for_def(db, def_id, None)
.fill(|x| {
let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
match x {
ParamKind::Type => ty.cast(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
.fill(|x| match x {
ParamKind::Type => {
generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
}
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
})
.build();
let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
@ -1159,21 +1159,6 @@ impl Struct {
Type::from_def(db, self.id)
}
pub fn ty_with_args(self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
let mut generics = generics.map(|it| it.ty.clone());
let substs = TyBuilder::subst_for_def(db, self.id, None)
.fill(|x| {
let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
match x {
ParamKind::Type => ty.cast(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
}
})
.build();
let ty = db.ty(self.id.into()).substitute(Interner, &substs);
Type::new(db, self.id, ty)
}
pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type {
Type::from_value_def(db, self.id)
}
@ -1273,22 +1258,6 @@ impl Enum {
Type::from_def(db, self.id)
}
pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
let mut generics = generics.map(|it| it.ty.clone());
let substs = TyBuilder::subst_for_def(db, self.id, None)
.fill(|x| {
let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
match x {
ParamKind::Type => ty.cast(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
}
})
.build();
let ty = db.ty(self.id.into()).substitute(Interner, &substs);
Type::new(db, self.id, ty)
}
/// The type of the enum variant bodies.
pub fn variant_body_ty(self, db: &dyn HirDatabase) -> Type {
Type::new_for_crate(
@ -1463,9 +1432,9 @@ impl Adt {
/// Turns this ADT into a type with the given type parameters. This isn't
/// the greatest API, FIXME find a better one.
pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
pub fn ty_with_args(self, db: &dyn HirDatabase, args: impl Iterator<Item = Type>) -> Type {
let id = AdtId::from(self);
let mut it = args.iter().map(|t| t.ty.clone());
let mut it = args.map(|t| t.ty.clone());
let ty = TyBuilder::def_ty(db, id.into(), None)
.fill(|x| {
let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
@ -1858,6 +1827,7 @@ impl Function {
Type::new_with_resolver_inner(db, &resolver, ty)
}
// FIXME: Find better API to also handle const generics
pub fn ret_type_with_args(
self,
db: &dyn HirDatabase,
@ -1870,12 +1840,11 @@ impl Function {
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
};
let mut generics = generics.map(|it| it.ty.clone());
let mut filler = |x: &_| {
let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
match x {
ParamKind::Type => ty.cast(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
let mut filler = |x: &_| match x {
ParamKind::Type => {
generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
}
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
};
let parent_substs =
@ -1953,10 +1922,11 @@ impl Function {
.collect()
}
pub fn params_without_self_with_generics(
// FIXME: Find better API to also handle const generics
pub fn params_without_self_with_args(
self,
db: &dyn HirDatabase,
mut generics: impl Iterator<Item = Type>,
generics: impl Iterator<Item = Type>,
) -> Vec<Param> {
let environment = db.trait_environment(self.id.into());
let parent_id: Option<GenericDefId> = match self.id.lookup(db.upcast()).container {
@ -1964,20 +1934,23 @@ impl Function {
ItemContainerId::TraitId(it) => Some(it.into()),
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
};
let mut generics = generics.map(|it| it.ty.clone());
let parent_substs = parent_id.map(|id| {
TyBuilder::subst_for_def(db, id, None)
.fill(|_| {
GenericArg::new(
Interner,
GenericArgData::Ty(generics.next().unwrap().ty.clone()),
)
.fill(|x| match x {
ParamKind::Type => generics
.next()
.unwrap_or_else(|| TyKind::Error.intern(Interner))
.cast(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
})
.build()
});
let substs = TyBuilder::subst_for_def(db, self.id, parent_substs)
.fill(|_| {
GenericArg::new(Interner, GenericArgData::Ty(generics.next().unwrap().ty.clone()))
let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
GenericArg::new(Interner, GenericArgData::Ty(ty))
})
.build();
let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
@ -2197,6 +2170,7 @@ impl SelfParam {
Type { env: environment, ty }
}
// FIXME: Find better API to also handle const generics
pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
let parent_id: GenericDefId = match self.func.lookup(db.upcast()).container {
ItemContainerId::ImplId(it) => it.into(),
@ -2207,12 +2181,11 @@ impl SelfParam {
};
let mut generics = generics.map(|it| it.ty.clone());
let mut filler = |x: &_| {
let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
match x {
ParamKind::Type => ty.cast(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
let mut filler = |x: &_| match x {
ParamKind::Type => {
generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
}
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
};
let parent_substs = TyBuilder::subst_for_def(db, parent_id, None).fill(&mut filler).build();
@ -2936,40 +2909,6 @@ impl GenericDef {
})
.collect()
}
pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> {
let generics = db.generic_params(self.into());
generics
.type_or_consts
.iter()
.filter_map(|(local_id, data)| match data {
hir_def::generics::TypeOrConstParamData::TypeParamData(_) => Some(TypeParam {
id: TypeParamId::from_unchecked(TypeOrConstParamId {
parent: self.into(),
local_id,
}),
}),
hir_def::generics::TypeOrConstParamData::ConstParamData(_) => None,
})
.collect()
}
pub fn const_params(self, db: &dyn HirDatabase) -> Vec<ConstParam> {
let generics = db.generic_params(self.into());
generics
.type_or_consts
.iter()
.filter_map(|(local_id, data)| match data {
hir_def::generics::TypeOrConstParamData::TypeParamData(_) => None,
hir_def::generics::TypeOrConstParamData::ConstParamData(_) => Some(ConstParam {
id: ConstParamId::from_unchecked(TypeOrConstParamId {
parent: self.into(),
local_id,
}),
}),
})
.collect()
}
}
/// A single local definition.
@ -3451,6 +3390,26 @@ impl TypeOrConstParam {
Either::Right(it) => it.ty(db),
}
}
pub fn as_type_param(self, db: &dyn HirDatabase) -> Option<TypeParam> {
let params = db.generic_params(self.id.parent);
match &params.type_or_consts[self.id.local_id] {
hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
Some(TypeParam { id: TypeParamId::from_unchecked(self.id) })
}
hir_def::generics::TypeOrConstParamData::ConstParamData(_) => None,
}
}
pub fn as_const_param(self, db: &dyn HirDatabase) -> Option<ConstParam> {
let params = db.generic_params(self.id.parent);
match &params.type_or_consts[self.id.local_id] {
hir_def::generics::TypeOrConstParamData::TypeParamData(_) => None,
hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
Some(ConstParam { id: ConstParamId::from_unchecked(self.id) })
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -3496,7 +3455,11 @@ impl Impl {
)
});
for Crate { id } in Crate::all(db) {
for id in def_crates
.iter()
.flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
.map(|Crate { id }| id)
{
all.extend(
db.trait_impls_in_crate(id)
.for_self_ty_without_blanket_impls(fp)
@ -3976,14 +3939,16 @@ impl Type {
)
}
// FIXME: Find better API that also handles const generics
pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
let mut it = args.iter().map(|t| t.ty.clone());
let trait_ref = TyBuilder::trait_ref(db, trait_.id)
.push(self.ty.clone())
.fill(|x| {
let r = it.next().unwrap();
match x {
ParamKind::Type => r.cast(Interner),
ParamKind::Type => {
it.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
}
ParamKind::Const(ty) => {
// FIXME: this code is not covered in tests.
unknown_const_as_generic(ty.clone())
@ -4617,12 +4582,19 @@ impl Type {
walk_type(db, self, &mut cb);
}
/// Check if type unifies with another type.
///
/// Note that we consider placeholder types to unify with everything.
/// For example `Option<T>` and `Option<U>` unify although there is unresolved goal `T = U`.
pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
hir_ty::could_unify(db, self.env.clone(), &tys)
}
/// Check if type unifies with another type eagerly making sure there are no unresolved goals.
///
/// This means that placeholder types are not considered to unify if there are any bounds set on
/// them. For example `Option<T>` and `Option<U>` do not unify as we cannot show that `T = U`
pub fn could_unify_with_deeply(&self, db: &dyn HirDatabase, other: &Type) -> bool {
let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
hir_ty::could_unify_deeply(db, self.env.clone(), &tys)

View file

@ -57,10 +57,10 @@ impl AlternativeExprs {
/// # Arguments
/// `threshold` - threshold value for many trees (more than that is many)
/// `exprs` - expressions iterator
fn extend_with_threshold(&mut self, threshold: usize, mut exprs: impl Iterator<Item = Expr>) {
fn extend_with_threshold(&mut self, threshold: usize, exprs: impl Iterator<Item = Expr>) {
match self {
AlternativeExprs::Few(tts) => {
while let Some(it) = exprs.next() {
for it in exprs {
if tts.len() > threshold {
*self = AlternativeExprs::Many;
break;
@ -131,7 +131,7 @@ impl LookupTable {
self.data
.iter()
.find(|(t, _)| {
Type::reference(t, Mutability::Shared).could_unify_with_deeply(db, &ty)
Type::reference(t, Mutability::Shared).could_unify_with_deeply(db, ty)
})
.map(|(t, it)| {
it.exprs(t)

View file

@ -2,7 +2,10 @@
use hir_def::find_path::PrefixKind;
use hir_expand::mod_path::ModPath;
use hir_ty::{db::HirDatabase, display::HirDisplay};
use hir_ty::{
db::HirDatabase,
display::{DisplaySourceCodeError, HirDisplay},
};
use itertools::Itertools;
use crate::{
@ -48,9 +51,10 @@ fn mod_item_path_str(
def: &ModuleDef,
prefer_no_std: bool,
prefer_prelude: bool,
) -> String {
) -> Result<String, DisplaySourceCodeError> {
let path = mod_item_path(sema_scope, def, prefer_no_std, prefer_prelude);
path.map(|it| it.display(sema_scope.db.upcast()).to_string()).unwrap()
path.map(|it| it.display(sema_scope.db.upcast()).to_string())
.ok_or(DisplaySourceCodeError::PathNotFound)
}
/// Helper function to get path to `Type`
@ -59,30 +63,34 @@ fn type_path(
ty: &Type,
prefer_no_std: bool,
prefer_prelude: bool,
) -> String {
) -> Result<String, DisplaySourceCodeError> {
let db = sema_scope.db;
let m = sema_scope.module();
match ty.as_adt() {
Some(adt) => {
let ty_name = ty.display(db).to_string();
let ty_name = ty.display_source_code(db, m.id, true)?;
let mut path =
mod_item_path(sema_scope, &ModuleDef::Adt(adt), prefer_no_std, prefer_prelude)
.unwrap();
path.pop_segment();
let path = path.display(db.upcast()).to_string();
match path.is_empty() {
let res = match path.is_empty() {
true => ty_name,
false => format!("{path}::{ty_name}"),
}
};
Ok(res)
}
None => ty.display(db).to_string(),
None => ty.display_source_code(db, m.id, true),
}
}
/// Helper function to filter out generic parameters that are default
fn non_default_generics(db: &dyn HirDatabase, def: GenericDef, generics: &[Type]) -> Vec<Type> {
def.type_params(db)
def.type_or_const_params(db)
.into_iter()
.filter_map(|it| it.as_type_param(db))
.zip(generics)
.filter(|(tp, arg)| tp.default(db).as_ref() != Some(arg))
.map(|(_, arg)| arg.clone())
@ -150,28 +158,30 @@ impl Expr {
many_formatter: &mut dyn FnMut(&Type) -> String,
prefer_no_std: bool,
prefer_prelude: bool,
) -> String {
) -> Result<String, DisplaySourceCodeError> {
let db = sema_scope.db;
let mod_item_path_str = |s, def| mod_item_path_str(s, def, prefer_no_std, prefer_prelude);
match self {
Expr::Const(it) => mod_item_path_str(sema_scope, &ModuleDef::Const(*it)),
Expr::Static(it) => mod_item_path_str(sema_scope, &ModuleDef::Static(*it)),
Expr::Local(it) => return it.name(db).display(db.upcast()).to_string(),
Expr::ConstParam(it) => return it.name(db).display(db.upcast()).to_string(),
Expr::FamousType { value, .. } => return value.to_string(),
Expr::Local(it) => Ok(it.name(db).display(db.upcast()).to_string()),
Expr::ConstParam(it) => Ok(it.name(db).display(db.upcast()).to_string()),
Expr::FamousType { value, .. } => Ok(value.to_string()),
Expr::Function { func, params, .. } => {
let args = params
.iter()
.map(|f| {
f.gen_source_code(sema_scope, many_formatter, prefer_no_std, prefer_prelude)
})
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
match func.as_assoc_item(db).map(|it| it.container(db)) {
Some(container) => {
let container_name = match container {
crate::AssocItemContainer::Trait(trait_) => {
mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))
mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?
}
crate::AssocItemContainer::Impl(imp) => {
let self_ty = imp.self_ty(db);
@ -190,17 +200,17 @@ impl Expr {
}
};
let fn_name = func.name(db).display(db.upcast()).to_string();
format!("{container_name}::{fn_name}({args})",)
Ok(format!("{container_name}::{fn_name}({args})"))
}
None => {
let fn_name = mod_item_path_str(sema_scope, &ModuleDef::Function(*func));
format!("{fn_name}({args})",)
let fn_name = mod_item_path_str(sema_scope, &ModuleDef::Function(*func))?;
Ok(format!("{fn_name}({args})"))
}
}
}
Expr::Method { func, target, params, .. } => {
if target.contains_many_in_illegal_pos() {
return many_formatter(&target.ty(db));
return Ok(many_formatter(&target.ty(db)));
}
let func_name = func.name(db).display(db.upcast()).to_string();
@ -210,28 +220,31 @@ impl Expr {
many_formatter,
prefer_no_std,
prefer_prelude,
);
)?;
let args = params
.iter()
.map(|f| {
f.gen_source_code(sema_scope, many_formatter, prefer_no_std, prefer_prelude)
})
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
match func.as_assoc_item(db).and_then(|it| it.containing_trait_or_trait_impl(db)) {
match func.as_assoc_item(db).and_then(|it| it.container_or_implemented_trait(db)) {
Some(trait_) => {
let trait_name = mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_));
let trait_name = mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?;
let target = match self_param.access(db) {
crate::Access::Shared => format!("&{target}"),
crate::Access::Exclusive => format!("&mut {target}"),
crate::Access::Owned => target,
};
match args.is_empty() {
let res = match args.is_empty() {
true => format!("{trait_name}::{func_name}({target})",),
false => format!("{trait_name}::{func_name}({target}, {args})",),
}
};
Ok(res)
}
None => format!("{target}.{func_name}({args})"),
None => Ok(format!("{target}.{func_name}({args})")),
}
}
Expr::Variant { variant, generics, params } => {
@ -242,6 +255,8 @@ impl Expr {
let generics = generics
.iter()
.map(|it| type_path(sema_scope, it, prefer_no_std, prefer_prelude))
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
format!("::<{generics}>")
}
@ -258,6 +273,8 @@ impl Expr {
prefer_prelude,
)
})
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
format!("{generics_str}({args})")
}
@ -267,25 +284,28 @@ impl Expr {
.iter()
.zip(fields.iter())
.map(|(a, f)| {
format!(
let tmp = format!(
"{}: {}",
f.name(db).display(db.upcast()).to_string(),
f.name(db).display(db.upcast()),
a.gen_source_code(
sema_scope,
many_formatter,
prefer_no_std,
prefer_prelude
)
)
)?
);
Ok(tmp)
})
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
format!("{generics_str}{{ {args} }}")
}
StructKind::Unit => generics_str,
};
let prefix = mod_item_path_str(sema_scope, &ModuleDef::Variant(*variant));
format!("{prefix}{inner}")
let prefix = mod_item_path_str(sema_scope, &ModuleDef::Variant(*variant))?;
Ok(format!("{prefix}{inner}"))
}
Expr::Struct { strukt, generics, params } => {
let generics = non_default_generics(db, (*strukt).into(), generics);
@ -301,6 +321,8 @@ impl Expr {
prefer_prelude,
)
})
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
format!("({args})")
}
@ -310,17 +332,20 @@ impl Expr {
.iter()
.zip(fields.iter())
.map(|(a, f)| {
format!(
let tmp = format!(
"{}: {}",
f.name(db).display(db.upcast()).to_string(),
f.name(db).display(db.upcast()),
a.gen_source_code(
sema_scope,
many_formatter,
prefer_no_std,
prefer_prelude
)
)
)?
);
Ok(tmp)
})
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
format!(" {{ {args} }}")
}
@ -330,35 +355,45 @@ impl Expr {
let generics = generics
.iter()
.map(|it| type_path(sema_scope, it, prefer_no_std, prefer_prelude))
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
format!("::<{generics}>")
}
},
};
let prefix = mod_item_path_str(sema_scope, &ModuleDef::Adt(Adt::Struct(*strukt)));
format!("{prefix}{inner}")
let prefix = mod_item_path_str(sema_scope, &ModuleDef::Adt(Adt::Struct(*strukt)))?;
Ok(format!("{prefix}{inner}"))
}
Expr::Field { expr, field } => {
if expr.contains_many_in_illegal_pos() {
return many_formatter(&expr.ty(db));
return Ok(many_formatter(&expr.ty(db)));
}
let strukt =
expr.gen_source_code(sema_scope, many_formatter, prefer_no_std, prefer_prelude);
let strukt = expr.gen_source_code(
sema_scope,
many_formatter,
prefer_no_std,
prefer_prelude,
)?;
let field = field.name(db).display(db.upcast()).to_string();
format!("{strukt}.{field}")
Ok(format!("{strukt}.{field}"))
}
Expr::Reference(expr) => {
if expr.contains_many_in_illegal_pos() {
return many_formatter(&expr.ty(db));
return Ok(many_formatter(&expr.ty(db)));
}
let inner =
expr.gen_source_code(sema_scope, many_formatter, prefer_no_std, prefer_prelude);
format!("&{inner}")
let inner = expr.gen_source_code(
sema_scope,
many_formatter,
prefer_no_std,
prefer_prelude,
)?;
Ok(format!("&{inner}"))
}
Expr::Many(ty) => many_formatter(ty),
Expr::Many(ty) => Ok(many_formatter(ty)),
}
}
@ -380,10 +415,10 @@ impl Expr {
target.ty(db).type_arguments().chain(generics.iter().cloned()),
),
Expr::Variant { variant, generics, .. } => {
variant.parent_enum(db).ty_with_args(db, generics.iter().cloned())
Adt::from(variant.parent_enum(db)).ty_with_args(db, generics.iter().cloned())
}
Expr::Struct { strukt, generics, .. } => {
strukt.ty_with_args(db, generics.iter().cloned())
Adt::from(*strukt).ty_with_args(db, generics.iter().cloned())
}
Expr::Field { expr, field } => field.ty_with_args(db, expr.ty(db).type_arguments()),
Expr::Reference(it) => it.ty(db),
@ -395,16 +430,13 @@ impl Expr {
pub fn traits_used(&self, db: &dyn HirDatabase) -> Vec<Trait> {
let mut res = Vec::new();
match self {
Expr::Method { func, params, .. } => {
res.extend(params.iter().flat_map(|it| it.traits_used(db)));
if let Some(it) = func.as_assoc_item(db) {
if let Some(it) = it.containing_trait_or_trait_impl(db) {
res.push(it);
}
if let Expr::Method { func, params, .. } = self {
res.extend(params.iter().flat_map(|it| it.traits_used(db)));
if let Some(it) = func.as_assoc_item(db) {
if let Some(it) = it.container_or_implemented_trait(db) {
res.push(it);
}
}
_ => (),
}
res

View file

@ -16,7 +16,7 @@ use rustc_hash::FxHashSet;
use crate::{
Adt, AssocItem, Enum, GenericDef, GenericParam, HasVisibility, Impl, ModuleDef, ScopeDef, Type,
Variant,
TypeParam, Variant,
};
use crate::term_search::{Expr, TermSearchConfig};
@ -82,7 +82,7 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
return None;
}
ty.could_unify_with_deeply(db, &ctx.goal).then(|| expr)
ty.could_unify_with_deeply(db, &ctx.goal).then_some(expr)
})
}
@ -118,11 +118,15 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
}
let generics = GenericDef::from(variant.parent_enum(db));
// Ignore enums with const generics
if !generics.const_params(db).is_empty() {
let Some(type_params) = generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()
else {
// Ignore enums with const generics
return Vec::new();
}
};
// We currently do not check lifetime bounds so ignore all types that have something to do
// with them
@ -130,9 +134,6 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
return Vec::new();
}
// Only account for stable type parameters for now
let type_params = generics.type_params(db);
// Only account for stable type parameters for now, unstable params can be default
// tho, for example in `Box<T, #[unstable] A: Allocator>`
if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
@ -154,13 +155,10 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
let mut g = generics.into_iter();
let generics: Vec<_> = type_params
.iter()
.map(|it| match it.default(db) {
Some(ty) => ty,
None => g.next().expect("Missing type param"),
})
.map(|it| it.default(db).unwrap_or_else(|| g.next().expect("No generic")))
.collect();
let enum_ty = parent_enum.ty_with_args(db, generics.iter().cloned());
let enum_ty = Adt::from(parent_enum).ty_with_args(db, generics.iter().cloned());
// Allow types with generics only if they take us straight to goal for
// performance reasons
@ -212,9 +210,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
let exprs: Vec<(Type, Vec<Expr>)> = enum_
.variants(db)
.into_iter()
.flat_map(|it| {
variant_helper(db, lookup, enum_.clone(), it, &ctx.goal, &ctx.config)
})
.flat_map(|it| variant_helper(db, lookup, *enum_, it, &ctx.goal, &ctx.config))
.collect();
if !exprs.is_empty() {
@ -231,10 +227,12 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
let generics = GenericDef::from(*it);
// Ignore enums with const generics
if !generics.const_params(db).is_empty() {
return None;
}
// Ignore const params for now
let type_params = generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()?;
// We currently do not check lifetime bounds so ignore all types that have something to do
// with them
@ -242,8 +240,6 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
return None;
}
let type_params = generics.type_params(db);
// Only account for stable type parameters for now, unstable params can be default
// tho, for example in `Box<T, #[unstable] A: Allocator>`
if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
@ -265,12 +261,13 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
let mut g = generics.into_iter();
let generics: Vec<_> = type_params
.iter()
.map(|it| match it.default(db) {
Some(ty) => ty,
None => g.next().expect("Missing type param"),
.map(|it| {
it.default(db)
.unwrap_or_else(|| g.next().expect("Missing type param"))
})
.collect();
let struct_ty = it.ty_with_args(db, generics.iter().cloned());
let struct_ty = Adt::from(*it).ty_with_args(db, generics.iter().cloned());
// Allow types with generics only if they take us straight to goal for
// performance reasons
@ -324,7 +321,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
_ => None,
})
.flatten()
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then(|| exprs))
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}
@ -352,18 +349,18 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
ScopeDef::ModuleDef(ModuleDef::Function(it)) => {
let generics = GenericDef::from(*it);
// Skip functions that require const generics
if !generics.const_params(db).is_empty() {
return None;
}
// Ignore const params for now
let type_params = generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()?;
// Ignore lifetimes as we do not check them
if !generics.lifetime_params(db).is_empty() {
return None;
}
let type_params = generics.type_params(db);
// Only account for stable type parameters for now, unstable params can be default
// tho, for example in `Box<T, #[unstable] A: Allocator>`
if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
@ -391,10 +388,14 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
let generics: Vec<_> = type_params
.iter()
.map(|it| match it.default(db) {
Some(ty) => ty,
None => g.next().expect("Missing type param"),
Some(ty) => Some(ty),
None => {
let generic = g.next().expect("Missing type param");
// Filter out generics that do not unify due to trait bounds
it.ty(db).could_unify_with(db, &generic).then_some(generic)
}
})
.collect();
.collect::<Option<_>>()?;
let ret_ty = it.ret_type_with_args(db, generics.iter().cloned());
// Filter out private and unsafe functions
@ -409,13 +410,13 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = it
.params_without_self_with_generics(db, generics.iter().cloned())
.params_without_self_with_args(db, generics.iter().cloned())
.into_iter()
.map(|field| {
let ty = field.ty();
match ty.is_mutable_reference() {
true => None,
false => lookup.find_autoref(db, &ty),
false => lookup.find_autoref(db, ty),
}
})
.collect::<Option<_>>()?;
@ -447,7 +448,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
_ => None,
})
.flatten()
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then(|| exprs))
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}
@ -487,11 +488,19 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
let fn_generics = GenericDef::from(it);
let imp_generics = GenericDef::from(imp);
// Ignore impl if it has const type arguments
if !fn_generics.const_params(db).is_empty() || !imp_generics.const_params(db).is_empty()
{
return None;
}
// Ignore const params for now
let imp_type_params = imp_generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()?;
// Ignore const params for now
let fn_type_params = fn_generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()?;
// Ignore all functions that have something to do with lifetimes as we don't check them
if !fn_generics.lifetime_params(db).is_empty() {
@ -508,9 +517,6 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
return None;
}
let imp_type_params = imp_generics.type_params(db);
let fn_type_params = fn_generics.type_params(db);
// Only account for stable type parameters for now, unstable params can be default
// tho, for example in `Box<T, #[unstable] A: Allocator>`
if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
@ -544,10 +550,14 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
.iter()
.chain(fn_type_params.iter())
.map(|it| match it.default(db) {
Some(ty) => ty,
None => g.next().expect("Missing type param"),
Some(ty) => Some(ty),
None => {
let generic = g.next().expect("Missing type param");
// Filter out generics that do not unify due to trait bounds
it.ty(db).could_unify_with(db, &generic).then_some(generic)
}
})
.collect();
.collect::<Option<_>>()?;
let ret_ty = it.ret_type_with_args(
db,
@ -579,16 +589,16 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = it
.params_without_self_with_generics(
.params_without_self_with_args(
db,
ty.type_arguments().chain(generics.iter().cloned()),
)
.into_iter()
.map(|field| lookup.find_autoref(db, &field.ty()))
.map(|field| lookup.find_autoref(db, field.ty()))
.collect::<Option<_>>()?;
let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
.chain(param_exprs.into_iter())
.chain(param_exprs)
.multi_cartesian_product()
.map(|params| {
let mut params = params.into_iter();
@ -609,7 +619,7 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
Some(exprs)
})
.flatten()
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then(|| exprs))
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}
@ -647,7 +657,7 @@ pub(super) fn struct_projection<'a, DB: HirDatabase>(
Some((filed_ty, exprs))
})
})
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then(|| exprs))
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}
@ -719,11 +729,19 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
let fn_generics = GenericDef::from(it);
let imp_generics = GenericDef::from(imp);
// Ignore impl if it has const type arguments
if !fn_generics.const_params(db).is_empty() || !imp_generics.const_params(db).is_empty()
{
return None;
}
// Ignore const params for now
let imp_type_params = imp_generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()?;
// Ignore const params for now
let fn_type_params = fn_generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()?;
// Ignore all functions that have something to do with lifetimes as we don't check them
if !fn_generics.lifetime_params(db).is_empty()
@ -742,9 +760,6 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
return None;
}
let imp_type_params = imp_generics.type_params(db);
let fn_type_params = fn_generics.type_params(db);
// Only account for stable type parameters for now, unstable params can be default
// tho, for example in `Box<T, #[unstable] A: Allocator>`
if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
@ -778,10 +793,17 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
.iter()
.chain(fn_type_params.iter())
.map(|it| match it.default(db) {
Some(ty) => ty,
None => g.next().expect("Missing type param"),
Some(ty) => Some(ty),
None => {
let generic = g.next().expect("Missing type param");
it.trait_bounds(db)
.into_iter()
.all(|bound| generic.impls_trait(db, bound, &[]));
// Filter out generics that do not unify due to trait bounds
it.ty(db).could_unify_with(db, &generic).then_some(generic)
}
})
.collect();
.collect::<Option<_>>()?;
let ret_ty = it.ret_type_with_args(
db,
@ -801,12 +823,12 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = it
.params_without_self_with_generics(
.params_without_self_with_args(
db,
ty.type_arguments().chain(generics.iter().cloned()),
)
.into_iter()
.map(|field| lookup.find_autoref(db, &field.ty()))
.map(|field| lookup.find_autoref(db, field.ty()))
.collect::<Option<_>>()?;
// Note that we need special case for 0 param constructors because of multi cartesian
@ -832,6 +854,6 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
Some(exprs)
})
.flatten()
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then(|| exprs))
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}