summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-ty
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-ty')
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml33
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/builder.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs83
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs41
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs236
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs122
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs378
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/interner.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs53
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs115
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs81
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs145
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs112
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs83
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs337
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs185
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/walk.rs147
30 files changed, 1312 insertions, 1047 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index ae837ac6d..a8b8d5222 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -2,9 +2,11 @@
name = "hir-ty"
version = "0.0.0"
description = "TBD"
-license = "MIT OR Apache-2.0"
-edition = "2021"
-rust-version = "1.65"
+
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+rust-version.workspace = true
[lib]
doctest = false
@@ -14,7 +16,7 @@ cov-mark = "2.0.0-pre.1"
itertools = "0.10.5"
arrayvec = "0.7.2"
bitflags = "1.3.2"
-smallvec = "1.10.0"
+smallvec.workspace = true
ena = "0.14.0"
tracing = "0.1.35"
rustc-hash = "1.1.0"
@@ -24,20 +26,21 @@ chalk-ir = "0.88.0"
chalk-recursive = { version = "0.88.0", default-features = false }
chalk-derive = "0.88.0"
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
-once_cell = "1.15.0"
+once_cell = "1.17.0"
typed-arena = "2.0.1"
rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false }
-stdx = { path = "../stdx", version = "0.0.0" }
-hir-def = { path = "../hir-def", version = "0.0.0" }
-hir-expand = { path = "../hir-expand", version = "0.0.0" }
-base-db = { path = "../base-db", version = "0.0.0" }
-profile = { path = "../profile", version = "0.0.0" }
-syntax = { path = "../syntax", version = "0.0.0" }
-limit = { path = "../limit", version = "0.0.0" }
+# local deps
+stdx.workspace = true
+intern.workspace = true
+hir-def.workspace = true
+hir-expand.workspace = true
+base-db.workspace = true
+profile.workspace = true
+syntax.workspace = true
+limit.workspace = true
[dev-dependencies]
-test-utils = { path = "../test-utils" }
expect-test = "1.4.0"
tracing = "0.1.35"
tracing-subscriber = { version = "0.3.16", default-features = false, features = [
@@ -45,3 +48,7 @@ tracing-subscriber = { version = "0.3.16", default-features = false, features =
"registry",
] }
tracing-tree = "0.2.1"
+project-model = { path = "../project-model" }
+
+# local deps
+test-utils.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index cbcf8f74c..58744dd0c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -6,9 +6,9 @@
use std::sync::Arc;
use chalk_ir::cast::Cast;
+use hir_def::lang_item::LangItem;
use hir_expand::name::name;
use limit::Limit;
-use syntax::SmolStr;
use crate::{
db::HirDatabase, infer::unify::InferenceTable, Canonical, Goal, Interner, ProjectionTyExt,
@@ -17,11 +17,13 @@ use crate::{
static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
+#[derive(Debug)]
pub(crate) enum AutoderefKind {
Builtin,
Overloaded,
}
+#[derive(Debug)]
pub(crate) struct Autoderef<'a, 'db> {
pub(crate) table: &'a mut InferenceTable<'db>,
ty: Ty,
@@ -117,9 +119,8 @@ fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
}
let db = table.db;
- let deref_trait = db
- .lang_item(table.trait_env.krate, SmolStr::new_inline("deref"))
- .and_then(|l| l.as_trait())?;
+ let deref_trait =
+ db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?;
let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
let projection = {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
index d5ef0c22d..8faef7bf7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
@@ -63,7 +63,7 @@ impl<D> TyBuilder<D> {
}
fn build_internal(self) -> (D, Substitution) {
- assert_eq!(self.vec.len(), self.param_kinds.len());
+ assert_eq!(self.vec.len(), self.param_kinds.len(), "{:?}", &self.param_kinds);
for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
self.assert_match_kind(a, e);
}
@@ -282,6 +282,21 @@ impl TyBuilder<Tuple> {
let (Tuple(size), subst) = self.build_internal();
TyKind::Tuple(size, subst).intern(Interner)
}
+
+ pub fn tuple_with<I>(elements: I) -> Ty
+ where
+ I: IntoIterator<Item = Ty>,
+ <I as IntoIterator>::IntoIter: ExactSizeIterator,
+ {
+ let elements = elements.into_iter();
+ let len = elements.len();
+ let mut b =
+ TyBuilder::new(Tuple(len), iter::repeat(ParamKind::Type).take(len).collect(), None);
+ for e in elements {
+ b = b.push(e);
+ }
+ b.build()
+ }
}
impl TyBuilder<TraitId> {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index 1c2b8de7f..6989e9fb9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -3,7 +3,6 @@
use std::sync::Arc;
use cov_mark::hit;
-use syntax::SmolStr;
use tracing::debug;
use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
@@ -12,7 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
use base_db::CrateId;
use hir_def::{
expr::Movability,
- lang_item::{lang_attr, LangItemTarget},
+ lang_item::{lang_attr, LangItem, LangItemTarget},
AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
};
use hir_expand::name::name;
@@ -182,9 +181,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
&self,
well_known_trait: rust_ir::WellKnownTrait,
) -> Option<chalk_ir::TraitId<Interner>> {
- let lang_attr = lang_attr_from_well_known_trait(well_known_trait);
+ let lang_attr = lang_item_from_well_known_trait(well_known_trait);
let trait_ = match self.db.lang_item(self.krate, lang_attr.into()) {
- Some(LangItemTarget::TraitId(trait_)) => trait_,
+ Some(LangItemTarget::Trait(trait_)) => trait_,
_ => return None,
};
Some(to_chalk_trait_id(trait_))
@@ -206,7 +205,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
.return_type_impl_traits(func)
.expect("impl trait id without impl traits");
let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
- let data = &datas.impl_traits[idx as usize];
+ let data = &datas.impl_traits[idx];
let bound = OpaqueTyDatumBound {
bounds: make_single_type_binders(data.bounds.skip_binders().to_vec()),
where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
@@ -216,7 +215,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
if let Some((future_trait, future_output)) = self
.db
- .lang_item(self.krate, SmolStr::new_inline("future_trait"))
+ .lang_item(self.krate, LangItem::Future)
.and_then(|item| item.as_trait())
.and_then(|trait_| {
let alias =
@@ -246,7 +245,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
binder.push(crate::wrap_empty_binders(impl_bound));
let sized_trait = self
.db
- .lang_item(self.krate, SmolStr::new_inline("sized"))
+ .lang_item(self.krate, LangItem::Sized)
.and_then(|item| item.as_trait());
if let Some(sized_trait_) = sized_trait {
let sized_bound = WhereClause::Implemented(TraitRef {
@@ -493,7 +492,7 @@ pub(crate) fn associated_ty_data_query(
if !ctx.unsized_types.borrow().contains(&self_ty) {
let sized_trait = db
- .lang_item(resolver.krate(), SmolStr::new_inline("sized"))
+ .lang_item(resolver.krate(), LangItem::Sized)
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
let sized_bound = sized_trait.into_iter().map(|sized_trait| {
let trait_bound =
@@ -541,8 +540,8 @@ pub(crate) fn trait_datum_query(
let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect();
let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses };
- let well_known =
- lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
+ let well_known = lang_attr(db.upcast(), trait_)
+ .and_then(|name| well_known_trait_from_lang_item(LangItem::from_str(&name)?));
let trait_datum = TraitDatum {
id: trait_id,
binders: make_binders(db, &generic_params, trait_datum_bound),
@@ -553,42 +552,42 @@ pub(crate) fn trait_datum_query(
Arc::new(trait_datum)
}
-fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> {
- Some(match name {
- "clone" => WellKnownTrait::Clone,
- "coerce_unsized" => WellKnownTrait::CoerceUnsized,
- "copy" => WellKnownTrait::Copy,
- "discriminant_kind" => WellKnownTrait::DiscriminantKind,
- "dispatch_from_dyn" => WellKnownTrait::DispatchFromDyn,
- "drop" => WellKnownTrait::Drop,
- "fn" => WellKnownTrait::Fn,
- "fn_mut" => WellKnownTrait::FnMut,
- "fn_once" => WellKnownTrait::FnOnce,
- "generator" => WellKnownTrait::Generator,
- "sized" => WellKnownTrait::Sized,
- "unpin" => WellKnownTrait::Unpin,
- "unsize" => WellKnownTrait::Unsize,
- "tuple_trait" => WellKnownTrait::Tuple,
+fn well_known_trait_from_lang_item(item: LangItem) -> Option<WellKnownTrait> {
+ Some(match item {
+ LangItem::Clone => WellKnownTrait::Clone,
+ LangItem::CoerceUnsized => WellKnownTrait::CoerceUnsized,
+ LangItem::Copy => WellKnownTrait::Copy,
+ LangItem::DiscriminantKind => WellKnownTrait::DiscriminantKind,
+ LangItem::DispatchFromDyn => WellKnownTrait::DispatchFromDyn,
+ LangItem::Drop => WellKnownTrait::Drop,
+ LangItem::Fn => WellKnownTrait::Fn,
+ LangItem::FnMut => WellKnownTrait::FnMut,
+ LangItem::FnOnce => WellKnownTrait::FnOnce,
+ LangItem::Generator => WellKnownTrait::Generator,
+ LangItem::Sized => WellKnownTrait::Sized,
+ LangItem::Unpin => WellKnownTrait::Unpin,
+ LangItem::Unsize => WellKnownTrait::Unsize,
+ LangItem::Tuple => WellKnownTrait::Tuple,
_ => return None,
})
}
-fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str {
- match attr {
- WellKnownTrait::Clone => "clone",
- WellKnownTrait::CoerceUnsized => "coerce_unsized",
- WellKnownTrait::Copy => "copy",
- WellKnownTrait::DiscriminantKind => "discriminant_kind",
- WellKnownTrait::DispatchFromDyn => "dispatch_from_dyn",
- WellKnownTrait::Drop => "drop",
- WellKnownTrait::Fn => "fn",
- WellKnownTrait::FnMut => "fn_mut",
- WellKnownTrait::FnOnce => "fn_once",
- WellKnownTrait::Generator => "generator",
- WellKnownTrait::Sized => "sized",
- WellKnownTrait::Tuple => "tuple_trait",
- WellKnownTrait::Unpin => "unpin",
- WellKnownTrait::Unsize => "unsize",
+fn lang_item_from_well_known_trait(trait_: WellKnownTrait) -> LangItem {
+ match trait_ {
+ WellKnownTrait::Clone => LangItem::Clone,
+ WellKnownTrait::CoerceUnsized => LangItem::CoerceUnsized,
+ WellKnownTrait::Copy => LangItem::Copy,
+ WellKnownTrait::DiscriminantKind => LangItem::DiscriminantKind,
+ WellKnownTrait::DispatchFromDyn => LangItem::DispatchFromDyn,
+ WellKnownTrait::Drop => LangItem::Drop,
+ WellKnownTrait::Fn => LangItem::Fn,
+ WellKnownTrait::FnMut => LangItem::FnMut,
+ WellKnownTrait::FnOnce => LangItem::FnOnce,
+ WellKnownTrait::Generator => LangItem::Generator,
+ WellKnownTrait::Sized => LangItem::Sized,
+ WellKnownTrait::Tuple => LangItem::Tuple,
+ WellKnownTrait::Unpin => LangItem::Unpin,
+ WellKnownTrait::Unsize => LangItem::Unsize,
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index 996b42f5b..45c975dfc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -1,13 +1,13 @@
//! Various extensions traits for Chalk types.
-use chalk_ir::{FloatTy, IntTy, Mutability, Scalar, UintTy};
+use chalk_ir::{FloatTy, IntTy, Mutability, Scalar, TyVariableKind, UintTy};
use hir_def::{
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint},
generics::TypeOrConstParamData,
+ lang_item::LangItem,
type_ref::Rawness,
FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
};
-use syntax::SmolStr;
use crate::{
db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
@@ -18,6 +18,8 @@ use crate::{
pub trait TyExt {
fn is_unit(&self) -> bool;
+ fn is_integral(&self) -> bool;
+ fn is_floating_point(&self) -> bool;
fn is_never(&self) -> bool;
fn is_unknown(&self) -> bool;
fn is_ty_var(&self) -> bool;
@@ -51,6 +53,21 @@ impl TyExt for Ty {
matches!(self.kind(Interner), TyKind::Tuple(0, _))
}
+ fn is_integral(&self) -> bool {
+ matches!(
+ self.kind(Interner),
+ TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
+ | TyKind::InferenceVar(_, TyVariableKind::Integer)
+ )
+ }
+
+ fn is_floating_point(&self) -> bool {
+ matches!(
+ self.kind(Interner),
+ TyKind::Scalar(Scalar::Float(_)) | TyKind::InferenceVar(_, TyVariableKind::Float)
+ )
+ }
+
fn is_never(&self) -> bool {
matches!(self.kind(Interner), TyKind::Never)
}
@@ -197,9 +214,8 @@ impl TyExt for Ty {
match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
let krate = def.module(db.upcast()).krate();
- if let Some(future_trait) = db
- .lang_item(krate, SmolStr::new_inline("future_trait"))
- .and_then(|item| item.as_trait())
+ if let Some(future_trait) =
+ db.lang_item(krate, LangItem::Future).and_then(|item| item.as_trait())
{
// This is only used by type walking.
// Parameters will be walked outside, and projection predicate is not used.
@@ -218,9 +234,8 @@ impl TyExt for Ty {
}
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
db.return_type_impl_traits(func).map(|it| {
- let data = (*it)
- .as_ref()
- .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
+ let data =
+ (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
data.substitute(Interner, &subst).into_value_and_skipped_binders().0
})
}
@@ -231,9 +246,8 @@ impl TyExt for Ty {
{
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
db.return_type_impl_traits(func).map(|it| {
- let data = (*it)
- .as_ref()
- .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
+ let data =
+ (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
data.substitute(Interner, &opaque_ty.substitution)
})
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 54b244620..d45e2a943 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -65,7 +65,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn layout_of_adt(&self, def: AdtId, subst: Substitution) -> Result<Layout, LayoutError>;
#[salsa::invoke(crate::layout::target_data_layout_query)]
- fn target_data_layout(&self, krate: CrateId) -> Arc<TargetDataLayout>;
+ fn target_data_layout(&self, krate: CrateId) -> Option<Arc<TargetDataLayout>>;
#[salsa::invoke(crate::lower::callable_item_sig)]
fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs
index 88d607194..2c1368962 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs
@@ -162,6 +162,7 @@ mod tests {
check(to_lower_snake_case, "a", expect![[""]]);
check(to_lower_snake_case, "abc", expect![[""]]);
check(to_lower_snake_case, "foo__bar", expect![["foo_bar"]]);
+ check(to_lower_snake_case, "Δ", expect!["δ"]);
}
#[test]
@@ -195,5 +196,6 @@ mod tests {
check(to_upper_snake_case, "X86_64", expect![[""]]);
check(to_upper_snake_case, "FOO_BAr", expect![["FOO_BAR"]]);
check(to_upper_snake_case, "FOO__BAR", expect![["FOO_BAR"]]);
+ check(to_upper_snake_case, "ß", expect!["SS"]);
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index c8df4c796..3286dcb5a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -5,7 +5,9 @@
use std::fmt;
use std::sync::Arc;
-use hir_def::{path::path, resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId, HasModule};
+use hir_def::lang_item::LangItem;
+use hir_def::{resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId, HasModule};
+use hir_def::{ItemContainerId, Lookup};
use hir_expand::name;
use itertools::Either;
use itertools::Itertools;
@@ -245,26 +247,25 @@ struct FilterMapNextChecker {
impl FilterMapNextChecker {
fn new(resolver: &hir_def::resolver::Resolver, db: &dyn HirDatabase) -> Self {
// Find and store the FunctionIds for Iterator::filter_map and Iterator::next
- let iterator_path = path![core::iter::Iterator];
- let mut filter_map_function_id = None;
- let mut next_function_id = None;
-
- if let Some(iterator_trait_id) = resolver.resolve_known_trait(db.upcast(), &iterator_path) {
- let iterator_trait_items = &db.trait_data(iterator_trait_id).items;
- for item in iterator_trait_items.iter() {
- if let (name, AssocItemId::FunctionId(id)) = item {
- if *name == name![filter_map] {
- filter_map_function_id = Some(*id);
+ let (next_function_id, filter_map_function_id) = match db
+ .lang_item(resolver.krate(), LangItem::IteratorNext)
+ .and_then(|it| it.as_function())
+ {
+ Some(next_function_id) => (
+ Some(next_function_id),
+ match next_function_id.lookup(db.upcast()).container {
+ ItemContainerId::TraitId(iterator_trait_id) => {
+ let iterator_trait_items = &db.trait_data(iterator_trait_id).items;
+ iterator_trait_items.iter().find_map(|(name, it)| match it {
+ &AssocItemId::FunctionId(id) if *name == name![filter_map] => Some(id),
+ _ => None,
+ })
}
- if *name == name![next] {
- next_function_id = Some(*id);
- }
- }
- if filter_map_function_id.is_some() && next_function_id.is_some() {
- break;
- }
- }
- }
+ _ => None,
+ },
+ ),
+ None => (None, None),
+ };
Self { filter_map_function_id, next_function_id, prev_filter_map_expr_id: None }
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 66e813eed..b22064d8c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -11,17 +11,17 @@ use hir_def::{
db::DefDatabase,
find_path,
generics::{TypeOrConstParamData, TypeParamProvenance},
- intern::{Internable, Interned},
item_scope::ItemInNs,
+ lang_item::{LangItem, LangItemTarget},
path::{Path, PathKind},
type_ref::{ConstScalar, TraitBoundModifier, TypeBound, TypeRef},
visibility::Visibility,
HasModule, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
};
use hir_expand::{hygiene::Hygiene, name::Name};
+use intern::{Internable, Interned};
use itertools::Itertools;
use smallvec::SmallVec;
-use syntax::SmolStr;
use crate::{
db::HirDatabase,
@@ -325,7 +325,7 @@ impl HirDisplay for ProjectionTy {
let trait_ref = self.trait_ref(f.db);
write!(f, "<")?;
- fmt_trait_ref(&trait_ref, f, true)?;
+ fmt_trait_ref(f, &trait_ref, true)?;
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
let proj_params_count =
self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
@@ -383,7 +383,10 @@ impl HirDisplay for BoundVar {
}
impl HirDisplay for Ty {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(
+ &self,
+ f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>,
+ ) -> Result<(), HirDisplayError> {
if f.should_truncate() {
return write!(f, "{TYPE_HINT_TRUNCATION}");
}
@@ -434,7 +437,7 @@ impl HirDisplay for Ty {
bounds.iter().any(|bound| {
if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
let trait_ = trait_ref.hir_trait_id();
- fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
+ fn_traits(db.upcast(), trait_).any(|it| it == trait_)
} else {
false
}
@@ -450,22 +453,20 @@ impl HirDisplay for Ty {
substitution: parameters,
}))
| TyKind::OpaqueType(opaque_ty_id, parameters) => {
- let impl_trait_id =
- f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
+ let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
- let datas =
- f.db.return_type_impl_traits(func)
- .expect("impl trait id without data");
- let data = (*datas)
- .as_ref()
- .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
+ let datas = db
+ .return_type_impl_traits(func)
+ .expect("impl trait id without data");
+ let data =
+ (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
let bounds = data.substitute(Interner, parameters);
let mut len = bounds.skip_binders().len();
// Don't count Sized but count when it absent
// (i.e. when explicit ?Sized bound is set).
let default_sized = SizedByDefault::Sized {
- anchor: func.lookup(f.db.upcast()).module(f.db.upcast()).krate(),
+ anchor: func.lookup(db.upcast()).module(db.upcast()).krate(),
};
let sized_bounds = bounds
.skip_binders()
@@ -476,7 +477,7 @@ impl HirDisplay for Ty {
WhereClause::Implemented(trait_ref)
if default_sized.is_sized_trait(
trait_ref.hir_trait_id(),
- f.db.upcast(),
+ db.upcast(),
),
)
})
@@ -524,19 +525,19 @@ impl HirDisplay for Ty {
sig.hir_fmt(f)?;
}
TyKind::FnDef(def, parameters) => {
- let def = from_chalk(f.db, *def);
- let sig = f.db.callable_item_signature(def).substitute(Interner, parameters);
+ let def = from_chalk(db, *def);
+ let sig = db.callable_item_signature(def).substitute(Interner, parameters);
+ f.start_location_link(def.into());
match def {
- CallableDefId::FunctionId(ff) => {
- write!(f, "fn {}", f.db.function_data(ff).name)?
- }
- CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?,
+ CallableDefId::FunctionId(ff) => write!(f, "fn {}", db.function_data(ff).name)?,
+ CallableDefId::StructId(s) => write!(f, "{}", db.struct_data(s).name)?,
CallableDefId::EnumVariantId(e) => {
- write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
+ write!(f, "{}", db.enum_data(e.parent).variants[e.local_id].name)?
}
};
+ f.end_location_link();
if parameters.len(Interner) > 0 {
- let generics = generics(f.db.upcast(), def.into());
+ let generics = generics(db.upcast(), def.into());
let (parent_params, self_param, type_params, const_params, _impl_trait_params) =
generics.provenance_split();
let total_len = parent_params + self_param + type_params + const_params;
@@ -568,15 +569,15 @@ impl HirDisplay for Ty {
match f.display_target {
DisplayTarget::Diagnostics | DisplayTarget::Test => {
let name = match *def_id {
- hir_def::AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
- hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
- hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
+ hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(),
+ hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(),
+ hir_def::AdtId::EnumId(it) => db.enum_data(it).name.clone(),
};
write!(f, "{name}")?;
}
DisplayTarget::SourceCode { module_id } => {
if let Some(path) = find_path::find_path(
- f.db.upcast(),
+ db.upcast(),
ItemInNs::Types((*def_id).into()),
module_id,
false,
@@ -596,8 +597,8 @@ impl HirDisplay for Ty {
|| f.omit_verbose_types()
{
match self
- .as_generic_def(f.db)
- .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
+ .as_generic_def(db)
+ .map(|generic_def_id| db.generic_defaults(generic_def_id))
.filter(|defaults| !defaults.is_empty())
{
None => parameters.as_slice(Interner),
@@ -669,16 +670,23 @@ impl HirDisplay for Ty {
}
TyKind::AssociatedType(assoc_type_id, parameters) => {
let type_alias = from_assoc_type_id(*assoc_type_id);
- let trait_ = match type_alias.lookup(f.db.upcast()).container {
+ let trait_ = match type_alias.lookup(db.upcast()).container {
ItemContainerId::TraitId(it) => it,
_ => panic!("not an associated type"),
};
- let trait_ = f.db.trait_data(trait_);
- let type_alias_data = f.db.type_alias_data(type_alias);
+ let trait_data = db.trait_data(trait_);
+ let type_alias_data = db.type_alias_data(type_alias);
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
if f.display_target.is_test() {
- write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
+ f.start_location_link(trait_.into());
+ write!(f, "{}", trait_data.name)?;
+ f.end_location_link();
+ write!(f, "::")?;
+
+ f.start_location_link(type_alias.into());
+ write!(f, "{}", type_alias_data.name)?;
+ f.end_location_link();
// Note that the generic args for the associated type come before those for the
// trait (including the self type).
// FIXME: reconsider the generic args order upon formatting?
@@ -697,30 +705,54 @@ impl HirDisplay for Ty {
}
}
TyKind::Foreign(type_alias) => {
- let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
+ let alias = from_foreign_def_id(*type_alias);
+ let type_alias = db.type_alias_data(alias);
+ f.start_location_link(alias.into());
write!(f, "{}", type_alias.name)?;
+ f.end_location_link();
}
TyKind::OpaqueType(opaque_ty_id, parameters) => {
- let impl_trait_id = f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
+ let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
match impl_trait_id {
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
let datas =
- f.db.return_type_impl_traits(func).expect("impl trait id without data");
- let data = (*datas)
- .as_ref()
- .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
+ db.return_type_impl_traits(func).expect("impl trait id without data");
+ let data =
+ (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
let bounds = data.substitute(Interner, &parameters);
- let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
+ let krate = func.lookup(db.upcast()).module(db.upcast()).krate();
write_bounds_like_dyn_trait_with_prefix(
+ f,
"impl",
bounds.skip_binders(),
SizedByDefault::Sized { anchor: krate },
- f,
)?;
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
}
- ImplTraitId::AsyncBlockTypeImplTrait(..) => {
- write!(f, "impl Future<Output = ")?;
+ ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => {
+ let future_trait = db
+ .lang_item(body.module(db.upcast()).krate(), LangItem::Future)
+ .and_then(LangItemTarget::as_trait);
+ let output = future_trait.and_then(|t| {
+ db.trait_data(t).associated_type_by_name(&hir_expand::name!(Output))
+ });
+ write!(f, "impl ")?;
+ if let Some(t) = future_trait {
+ f.start_location_link(t.into());
+ }
+ write!(f, "Future")?;
+ if let Some(_) = future_trait {
+ f.end_location_link();
+ }
+ write!(f, "<")?;
+ if let Some(t) = output {
+ f.start_location_link(t.into());
+ }
+ write!(f, "Output")?;
+ if let Some(_) = output {
+ f.end_location_link();
+ }
+ write!(f, " = ")?;
parameters.at(Interner, 0).hir_fmt(f)?;
write!(f, ">")?;
}
@@ -732,7 +764,7 @@ impl HirDisplay for Ty {
DisplaySourceCodeError::Closure,
));
}
- let sig = substs.at(Interner, 0).assert_ty_ref(Interner).callable_sig(f.db);
+ let sig = substs.at(Interner, 0).assert_ty_ref(Interner).callable_sig(db);
if let Some(sig) = sig {
if sig.params().is_empty() {
write!(f, "||")?;
@@ -751,8 +783,8 @@ impl HirDisplay for Ty {
}
}
TyKind::Placeholder(idx) => {
- let id = from_placeholder_idx(f.db, *idx);
- let generics = generics(f.db.upcast(), id.parent);
+ let id = from_placeholder_idx(db, *idx);
+ let generics = generics(db.upcast(), id.parent);
let param_data = &generics.params.type_or_consts[id.local_id];
match param_data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
@@ -760,28 +792,28 @@ impl HirDisplay for Ty {
write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))?
}
TypeParamProvenance::ArgumentImplTrait => {
- let substs = generics.placeholder_subst(f.db);
- let bounds =
- f.db.generic_predicates(id.parent)
- .iter()
- .map(|pred| pred.clone().substitute(Interner, &substs))
- .filter(|wc| match &wc.skip_binders() {
- WhereClause::Implemented(tr) => {
- &tr.self_type_parameter(Interner) == self
- }
- WhereClause::AliasEq(AliasEq {
- alias: AliasTy::Projection(proj),
- ty: _,
- }) => &proj.self_type_parameter(f.db) == self,
- _ => false,
- })
- .collect::<Vec<_>>();
- let krate = id.parent.module(f.db.upcast()).krate();
+ let substs = generics.placeholder_subst(db);
+ let bounds = db
+ .generic_predicates(id.parent)
+ .iter()
+ .map(|pred| pred.clone().substitute(Interner, &substs))
+ .filter(|wc| match &wc.skip_binders() {
+ WhereClause::Implemented(tr) => {
+ &tr.self_type_parameter(Interner) == self
+ }
+ WhereClause::AliasEq(AliasEq {
+ alias: AliasTy::Projection(proj),
+ ty: _,
+ }) => &proj.self_type_parameter(db) == self,
+ _ => false,
+ })
+ .collect::<Vec<_>>();
+ let krate = id.parent.module(db.upcast()).krate();
write_bounds_like_dyn_trait_with_prefix(
+ f,
"impl",
&bounds,
SizedByDefault::Sized { anchor: krate },
- f,
)?;
}
},
@@ -803,29 +835,28 @@ impl HirDisplay for Ty {
bounds.extend(auto_traits);
write_bounds_like_dyn_trait_with_prefix(
+ f,
"dyn",
&bounds,
SizedByDefault::NotSized,
- f,
)?;
}
TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
- let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
+ let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
match impl_trait_id {
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
let datas =
- f.db.return_type_impl_traits(func).expect("impl trait id without data");
- let data = (*datas)
- .as_ref()
- .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
+ db.return_type_impl_traits(func).expect("impl trait id without data");
+ let data =
+ (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
let bounds = data.substitute(Interner, &opaque_ty.substitution);
- let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
+ let krate = func.lookup(db.upcast()).module(db.upcast()).krate();
write_bounds_like_dyn_trait_with_prefix(
+ f,
"impl",
bounds.skip_binders(),
SizedByDefault::Sized { anchor: krate },
- f,
)?;
}
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
@@ -848,7 +879,6 @@ impl HirDisplay for Ty {
DisplaySourceCodeError::Generator,
));
}
-
let subst = subst.as_slice(Interner);
let a: Option<SmallVec<[&Ty; 3]>> = subst
.get(subst.len() - 3..)
@@ -897,7 +927,7 @@ impl HirDisplay for CallableSig {
}
}
-fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
+fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> + '_ {
let krate = trait_.lookup(db).container.krate();
utils::fn_traits(db, krate)
}
@@ -914,7 +944,7 @@ impl SizedByDefault {
Self::NotSized => false,
Self::Sized { anchor } => {
let sized_trait = db
- .lang_item(anchor, SmolStr::new_inline("sized"))
+ .lang_item(anchor, LangItem::Sized)
.and_then(|lang_item| lang_item.as_trait());
Some(trait_) == sized_trait
}
@@ -923,26 +953,26 @@ impl SizedByDefault {
}
pub fn write_bounds_like_dyn_trait_with_prefix(
+ f: &mut HirFormatter<'_>,
prefix: &str,
predicates: &[QuantifiedWhereClause],
default_sized: SizedByDefault,
- f: &mut HirFormatter<'_>,
) -> Result<(), HirDisplayError> {
write!(f, "{prefix}")?;
if !predicates.is_empty()
|| predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
{
write!(f, " ")?;
- write_bounds_like_dyn_trait(predicates, default_sized, f)
+ write_bounds_like_dyn_trait(f, predicates, default_sized)
} else {
Ok(())
}
}
fn write_bounds_like_dyn_trait(
+ f: &mut HirFormatter<'_>,
predicates: &[QuantifiedWhereClause],
default_sized: SizedByDefault,
- f: &mut HirFormatter<'_>,
) -> Result<(), HirDisplayError> {
// Note: This code is written to produce nice results (i.e.
// corresponding to surface Rust) for types that can occur in
@@ -978,7 +1008,9 @@ fn write_bounds_like_dyn_trait(
// We assume that the self type is ^0.0 (i.e. the
// existential) here, which is the only thing that's
// possible in actual Rust, and hence don't print it
+ f.start_location_link(trait_.into());
write!(f, "{}", f.db.trait_data(trait_).name)?;
+ f.end_location_link();
if let [_, params @ ..] = &*trait_ref.substitution.as_slice(Interner) {
if is_fn_trait {
if let Some(args) =
@@ -1015,7 +1047,9 @@ fn write_bounds_like_dyn_trait(
if let AliasTy::Projection(proj) = alias {
let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
let type_alias = f.db.type_alias_data(assoc_ty_id);
+ f.start_location_link(assoc_ty_id.into());
write!(f, "{}", type_alias.name)?;
+ f.end_location_link();
let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
if proj_arg_count > 0 {
@@ -1040,19 +1074,33 @@ fn write_bounds_like_dyn_trait(
if angle_open {
write!(f, ">")?;
}
- if matches!(default_sized, SizedByDefault::Sized { .. }) {
+ if let SizedByDefault::Sized { anchor } = default_sized {
+ let sized_trait =
+ f.db.lang_item(anchor, LangItem::Sized).and_then(|lang_item| lang_item.as_trait());
if !is_sized {
- write!(f, "{}?Sized", if first { "" } else { " + " })?;
+ if !first {
+ write!(f, " + ")?;
+ }
+ if let Some(sized_trait) = sized_trait {
+ f.start_location_link(sized_trait.into());
+ }
+ write!(f, "?Sized")?;
} else if first {
+ if let Some(sized_trait) = sized_trait {
+ f.start_location_link(sized_trait.into());
+ }
write!(f, "Sized")?;
}
+ if let Some(_) = sized_trait {
+ f.end_location_link();
+ }
}
Ok(())
}
fn fmt_trait_ref(
- tr: &TraitRef,
f: &mut HirFormatter<'_>,
+ tr: &TraitRef,
use_as: bool,
) -> Result<(), HirDisplayError> {
if f.should_truncate() {
@@ -1065,7 +1113,10 @@ fn fmt_trait_ref(
} else {
write!(f, ": ")?;
}
- write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
+ let trait_ = tr.hir_trait_id();
+ f.start_location_link(trait_.into());
+ write!(f, "{}", f.db.trait_data(trait_).name)?;
+ f.end_location_link();
if tr.substitution.len(Interner) > 1 {
write!(f, "<")?;
f.write_joined(&tr.substitution.as_slice(Interner)[1..], ", ")?;
@@ -1076,7 +1127,7 @@ fn fmt_trait_ref(
impl HirDisplay for TraitRef {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- fmt_trait_ref(self, f, false)
+ fmt_trait_ref(f, self, false)
}
}
@@ -1090,12 +1141,13 @@ impl HirDisplay for WhereClause {
WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
write!(f, "<")?;
- fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?;
- write!(
- f,
- ">::{} = ",
- f.db.type_alias_data(from_assoc_type_id(projection_ty.associated_ty_id)).name,
- )?;
+ fmt_trait_ref(f, &projection_ty.trait_ref(f.db), true)?;
+ write!(f, ">::",)?;
+ let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
+ f.start_location_link(type_alias.into());
+ write!(f, "{}", f.db.type_alias_data(type_alias).name,)?;
+ f.end_location_link();
+ write!(f, " = ")?;
ty.hir_fmt(f)?;
}
WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
@@ -1367,7 +1419,7 @@ impl HirDisplay for Path {
write!(f, "<")?;
let mut first = true;
- for arg in &generic_args.args {
+ for arg in generic_args.args.iter() {
if first {
first = false;
if generic_args.has_self_type {
@@ -1379,7 +1431,7 @@ impl HirDisplay for Path {
}
arg.hir_fmt(f)?;
}
- for binding in &generic_args.bindings {
+ for binding in generic_args.bindings.iter() {
if first {
first = false;
} else {
@@ -1393,7 +1445,7 @@ impl HirDisplay for Path {
}
None => {
write!(f, ": ")?;
- f.write_joined(&binding.bounds, " + ")?;
+ f.write_joined(binding.bounds.iter(), " + ")?;
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 6b59f1c20..767afdf9e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -22,15 +22,15 @@ use hir_def::{
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
data::{ConstData, StaticData},
expr::{BindingAnnotation, ExprId, ExprOrPatId, PatId},
- lang_item::LangItemTarget,
+ lang_item::{LangItem, LangItemTarget},
layout::Integer,
- path::{path, Path},
+ path::Path,
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
type_ref::TypeRef,
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
};
-use hir_expand::name::{name, Name};
+use hir_expand::name::name;
use itertools::Either;
use la_arena::ArenaMap;
use rustc_hash::FxHashMap;
@@ -39,7 +39,7 @@ use stdx::always;
use crate::{
db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
- GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, Substitution,
+ GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution,
TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
};
@@ -219,6 +219,7 @@ struct InternedStandardTypes {
unknown: Ty,
bool_: Ty,
unit: Ty,
+ never: Ty,
}
impl Default for InternedStandardTypes {
@@ -227,6 +228,7 @@ impl Default for InternedStandardTypes {
unknown: TyKind::Error.intern(Interner),
bool_: TyKind::Scalar(Scalar::Bool).intern(Interner),
unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
+ never: TyKind::Never.intern(Interner),
}
}
}
@@ -352,6 +354,7 @@ pub struct InferenceResult {
/// **Note**: When a pattern type is resolved it may still contain
/// unresolved or missing subpatterns or subpatterns of mismatched types.
pub type_of_pat: ArenaMap<PatId, Ty>,
+ pub type_of_rpit: ArenaMap<RpitId, Ty>,
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
/// Interned common types to return references to.
standard_types: InternedStandardTypes,
@@ -525,6 +528,9 @@ impl<'a> InferenceContext<'a> {
for ty in result.type_of_pat.values_mut() {
*ty = table.resolve_completely(ty.clone());
}
+ for ty in result.type_of_rpit.iter_mut().map(|x| x.1) {
+ *ty = table.resolve_completely(ty.clone());
+ }
for mismatch in result.type_mismatches.values_mut() {
mismatch.expected = table.resolve_completely(mismatch.expected.clone());
mismatch.actual = table.resolve_completely(mismatch.actual.clone());
@@ -603,7 +609,7 @@ impl<'a> InferenceContext<'a> {
_ => unreachable!(),
};
let bounds = (*rpits).map_ref(|rpits| {
- rpits.impl_traits[idx as usize].bounds.map_ref(|it| it.into_iter())
+ rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter())
});
let var = self.table.new_type_var();
let var_subst = Substitution::from1(Interner, var.clone());
@@ -616,6 +622,7 @@ impl<'a> InferenceContext<'a> {
always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
self.push_obligation(var_predicate.cast(Interner));
}
+ self.result.type_of_rpit.insert(idx, var.clone());
var
},
DebruijnIndex::INNERMOST,
@@ -917,104 +924,98 @@ impl<'a> InferenceContext<'a> {
}
}
- fn resolve_lang_item(&self, name: Name) -> Option<LangItemTarget> {
+ fn resolve_lang_item(&self, item: LangItem) -> Option<LangItemTarget> {
let krate = self.resolver.krate();
- self.db.lang_item(krate, name.to_smol_str())
+ self.db.lang_item(krate, item)
}
fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
- let path = path![core::iter::IntoIterator];
- let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
+ let ItemContainerId::TraitId(trait_) = self.resolve_lang_item(LangItem::IntoIterIntoIter)?
+ .as_function()?
+ .lookup(self.db.upcast()).container
+ else { return None };
self.db.trait_data(trait_).associated_type_by_name(&name![IntoIter])
}
fn resolve_iterator_item(&self) -> Option<TypeAliasId> {
- let path = path![core::iter::Iterator];
- let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
+ let ItemContainerId::TraitId(trait_) = self.resolve_lang_item(LangItem::IteratorNext)?
+ .as_function()?
+ .lookup(self.db.upcast()).container
+ else { return None };
self.db.trait_data(trait_).associated_type_by_name(&name![Item])
}
- fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
- // FIXME resolve via lang_item once try v2 is stable
- let path = path![core::ops::Try];
- let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
- let trait_data = self.db.trait_data(trait_);
- trait_data
- // FIXME remove once try v2 is stable
- .associated_type_by_name(&name![Ok])
- .or_else(|| trait_data.associated_type_by_name(&name![Output]))
+ fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> {
+ self.db.trait_data(trait_).associated_type_by_name(&name![Output])
+ }
+
+ fn resolve_lang_trait(&self, lang: LangItem) -> Option<TraitId> {
+ self.resolve_lang_item(lang)?.as_trait()
+ }
+
+ fn resolve_ops_try_output(&self) -> Option<TypeAliasId> {
+ self.resolve_output_on(self.resolve_lang_trait(LangItem::Try)?)
}
fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
- let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?;
- self.db.trait_data(trait_).associated_type_by_name(&name![Output])
+ self.resolve_output_on(self.resolve_lang_trait(LangItem::Neg)?)
}
fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
- let trait_ = self.resolve_lang_item(name![not])?.as_trait()?;
- self.db.trait_data(trait_).associated_type_by_name(&name![Output])
+ self.resolve_output_on(self.resolve_lang_trait(LangItem::Not)?)
}
fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
- let trait_ = self
- .resolver
- .resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture])
- .or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?;
- self.db.trait_data(trait_).associated_type_by_name(&name![Output])
+ let ItemContainerId::TraitId(trait_) = self
+ .resolve_lang_item(LangItem::IntoFutureIntoFuture)?
+ .as_function()?
+ .lookup(self.db.upcast())
+ .container
+ else { return None };
+ self.resolve_output_on(trait_)
}
fn resolve_boxed_box(&self) -> Option<AdtId> {
- let struct_ = self.resolve_lang_item(name![owned_box])?.as_struct()?;
+ let struct_ = self.resolve_lang_item(LangItem::OwnedBox)?.as_struct()?;
Some(struct_.into())
}
fn resolve_range_full(&self) -> Option<AdtId> {
- let path = path![core::ops::RangeFull];
- let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
+ let struct_ = self.resolve_lang_item(LangItem::RangeFull)?.as_struct()?;
Some(struct_.into())
}
fn resolve_range(&self) -> Option<AdtId> {
- let path = path![core::ops::Range];
- let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
+ let struct_ = self.resolve_lang_item(LangItem::Range)?.as_struct()?;
Some(struct_.into())
}
fn resolve_range_inclusive(&self) -> Option<AdtId> {
- let path = path![core::ops::RangeInclusive];
- let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
+ let struct_ = self.resolve_lang_item(LangItem::RangeInclusiveStruct)?.as_struct()?;
Some(struct_.into())
}
fn resolve_range_from(&self) -> Option<AdtId> {
- let path = path![core::ops::RangeFrom];
- let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
+ let struct_ = self.resolve_lang_item(LangItem::RangeFrom)?.as_struct()?;
Some(struct_.into())
}
fn resolve_range_to(&self) -> Option<AdtId> {
- let path = path![core::ops::RangeTo];
- let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
+ let struct_ = self.resolve_lang_item(LangItem::RangeTo)?.as_struct()?;
Some(struct_.into())
}
fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
- let path = path![core::ops::RangeToInclusive];
- let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
+ let struct_ = self.resolve_lang_item(LangItem::RangeToInclusive)?.as_struct()?;
Some(struct_.into())
}
- fn resolve_ops_index(&self) -> Option<TraitId> {
- self.resolve_lang_item(name![index])?.as_trait()
- }
-
fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
- let trait_ = self.resolve_ops_index()?;
- self.db.trait_data(trait_).associated_type_by_name(&name![Output])
+ self.resolve_output_on(self.resolve_lang_trait(LangItem::Index)?)
}
fn resolve_va_list(&self) -> Option<AdtId> {
- let struct_ = self.resolve_lang_item(name![va_list])?.as_struct()?;
+ let struct_ = self.resolve_lang_item(LangItem::VaList)?.as_struct()?;
Some(struct_.into())
}
}
@@ -1025,7 +1026,8 @@ impl<'a> InferenceContext<'a> {
pub(crate) enum Expectation {
None,
HasType(Ty),
- // Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts
+ #[allow(dead_code)]
+ Castable(Ty),
RValueLikeUnsized(Ty),
}
@@ -1041,10 +1043,6 @@ impl Expectation {
}
}
- fn from_option(ty: Option<Ty>) -> Self {
- ty.map_or(Expectation::None, Expectation::HasType)
- }
-
/// The following explanation is copied straight from rustc:
/// Provides an expectation for an rvalue expression given an *optional*
/// hint, which is not required for type safety (the resulting type might
@@ -1082,6 +1080,7 @@ impl Expectation {
match self {
Expectation::None => Expectation::None,
Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)),
+ Expectation::Castable(t) => Expectation::Castable(table.resolve_ty_shallow(t)),
Expectation::RValueLikeUnsized(t) => {
Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t))
}
@@ -1091,20 +1090,25 @@ impl Expectation {
fn to_option(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
match self.resolve(table) {
Expectation::None => None,
- Expectation::HasType(t) |
- // Expectation::Castable(t) |
- Expectation::RValueLikeUnsized(t) => Some(t),
+ Expectation::HasType(t)
+ | Expectation::Castable(t)
+ | Expectation::RValueLikeUnsized(t) => Some(t),
}
}
fn only_has_type(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
match self {
Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)),
- // Expectation::Castable(_) |
- Expectation::RValueLikeUnsized(_) | Expectation::None => None,
+ Expectation::Castable(_) | Expectation::RValueLikeUnsized(_) | Expectation::None => {
+ None
+ }
}
}
+ fn coercion_target_type(&self, table: &mut unify::InferenceTable<'_>) -> Ty {
+ self.only_has_type(table).unwrap_or_else(|| table.new_type_var())
+ }
+
/// Comment copied from rustc:
/// Disregard "castable to" expectations because they
/// can lead us astray. Consider for example `if cond
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index 094e460db..a6449d019 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -51,7 +51,7 @@ impl InferenceContext<'_> {
.map(to_chalk_trait_id)
.collect();
- let self_ty = TyKind::Error.intern(Interner);
+ let self_ty = self.result.standard_types.unknown.clone();
let bounds = dyn_ty.bounds.clone().substitute(Interner, &[self_ty.cast(Interner)]);
for bound in bounds.iter(Interner) {
// NOTE(skip_binders): the extracted types are rebound by the returned `FnPointer`
@@ -67,7 +67,7 @@ impl InferenceContext<'_> {
let arg = projection.substitution.as_slice(Interner).get(1)?;
if let Some(subst) = arg.ty(Interner)?.as_tuple() {
let generic_args = subst.as_slice(Interner);
- let mut sig_tys = Vec::new();
+ let mut sig_tys = Vec::with_capacity(generic_args.len() + 1);
for arg in generic_args {
sig_tys.push(arg.ty(Interner)?.clone());
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
index 8df25c83c..3293534a0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
@@ -8,9 +8,11 @@
use std::{iter, sync::Arc};
use chalk_ir::{cast::Cast, BoundVar, Goal, Mutability, TyVariableKind};
-use hir_def::{expr::ExprId, lang_item::LangItemTarget};
+use hir_def::{
+ expr::ExprId,
+ lang_item::{LangItem, LangItemTarget},
+};
use stdx::always;
-use syntax::SmolStr;
use crate::{
autoderef::{Autoderef, AutoderefKind},
@@ -570,11 +572,10 @@ impl<'a> InferenceTable<'a> {
reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone());
let krate = self.trait_env.krate;
- let coerce_unsized_trait =
- match self.db.lang_item(krate, SmolStr::new_inline("coerce_unsized")) {
- Some(LangItemTarget::TraitId(trait_)) => trait_,
- _ => return Err(TypeError),
- };
+ let coerce_unsized_trait = match self.db.lang_item(krate, LangItem::CoerceUnsized) {
+ Some(LangItemTarget::Trait(trait_)) => trait_,
+ _ => return Err(TypeError),
+ };
let coerce_unsized_tref = {
let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 8f9cdac37..175fded8c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -10,15 +10,15 @@ use chalk_ir::{
};
use hir_def::{
expr::{
- ArithOp, Array, BinaryOp, ClosureKind, CmpOp, Expr, ExprId, LabelId, Literal, Statement,
- UnaryOp,
+ ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
},
generics::TypeOrConstParamData,
+ lang_item::LangItem,
path::{GenericArg, GenericArgs},
resolver::resolver_for_expr,
ConstParamId, FieldId, ItemContainerId, Lookup,
};
-use hir_expand::name::Name;
+use hir_expand::name::{name, Name};
use stdx::always;
use syntax::ast::RangeOp;
@@ -30,7 +30,7 @@ use crate::{
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
},
mapping::{from_chalk, ToChalk},
- method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
+ method_resolution::{self, lang_items_for_bin_op, VisibleFromModule},
primitive::{self, UintTy},
static_lifetime, to_chalk_trait_id,
utils::{generics, Generics},
@@ -87,16 +87,15 @@ impl<'a> InferenceContext<'a> {
let expected = &expected.adjust_for_branches(&mut self.table);
self.infer_expr(
condition,
- &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
+ &Expectation::HasType(self.result.standard_types.bool_.clone()),
);
let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let mut both_arms_diverge = Diverges::Always;
- let result_ty = self.table.new_type_var();
let then_ty = self.infer_expr_inner(then_branch, expected);
both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
- let mut coerce = CoerceMany::new(result_ty);
+ let mut coerce = CoerceMany::new(expected.coercion_target_type(&mut self.table));
coerce.coerce(self, Some(then_branch), &then_ty);
let else_ty = match else_branch {
Some(else_branch) => self.infer_expr_inner(else_branch, expected),
@@ -113,7 +112,7 @@ impl<'a> InferenceContext<'a> {
&Expr::Let { pat, expr } => {
let input_ty = self.infer_expr(expr, &Expectation::none());
self.infer_pat(pat, &input_ty, BindingMode::default());
- TyKind::Scalar(Scalar::Bool).intern(Interner)
+ self.result.standard_types.bool_.clone()
}
Expr::Block { statements, tail, label, id: _ } => {
let old_resolver = mem::replace(
@@ -158,7 +157,8 @@ impl<'a> InferenceContext<'a> {
}
// The ok-ish type that is expected from the last expression
- let ok_ty = self.resolve_associated_type(try_ty.clone(), self.resolve_ops_try_ok());
+ let ok_ty =
+ self.resolve_associated_type(try_ty.clone(), self.resolve_ops_try_output());
self.with_breakable_ctx(BreakableKind::Block, ok_ty.clone(), None, |this| {
this.infer_expr(*body, &Expectation::has_type(ok_ty));
@@ -187,10 +187,12 @@ impl<'a> InferenceContext<'a> {
.intern(Interner)
}
&Expr::Loop { body, label } => {
+ // FIXME: should be:
+ // let ty = expected.coercion_target_type(&mut self.table);
let ty = self.table.new_type_var();
let (breaks, ()) =
self.with_breakable_ctx(BreakableKind::Loop, ty, label, |this| {
- this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+ this.infer_expr(body, &Expectation::HasType(TyBuilder::unit()));
});
match breaks {
@@ -198,16 +200,16 @@ impl<'a> InferenceContext<'a> {
self.diverges = Diverges::Maybe;
breaks
}
- None => TyKind::Never.intern(Interner),
+ None => self.result.standard_types.never.clone(),
}
}
&Expr::While { condition, body, label } => {
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
this.infer_expr(
condition,
- &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
+ &Expectation::HasType(this.result.standard_types.bool_.clone()),
);
- this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+ this.infer_expr(body, &Expectation::HasType(TyBuilder::unit()));
});
// the body may not run, so it diverging doesn't mean we diverge
@@ -223,7 +225,7 @@ impl<'a> InferenceContext<'a> {
self.infer_pat(pat, &pat_ty, BindingMode::default());
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
- this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+ this.infer_expr(body, &Expectation::HasType(TyBuilder::unit()));
});
// the body may not run, so it diverging doesn't mean we diverge
@@ -233,7 +235,7 @@ impl<'a> InferenceContext<'a> {
Expr::Closure { body, args, ret_type, arg_types, closure_kind } => {
assert_eq!(args.len(), arg_types.len());
- let mut sig_tys = Vec::new();
+ let mut sig_tys = Vec::with_capacity(arg_types.len() + 1);
// collect explicitly written argument types
for arg_type in arg_types.iter() {
@@ -254,7 +256,8 @@ impl<'a> InferenceContext<'a> {
num_binders: 0,
sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
substitution: FnSubst(
- Substitution::from_iter(Interner, sig_tys.clone()).shifted_in(Interner),
+ Substitution::from_iter(Interner, sig_tys.iter().cloned())
+ .shifted_in(Interner),
),
})
.intern(Interner);
@@ -316,27 +319,34 @@ impl<'a> InferenceContext<'a> {
Expr::Call { callee, args, .. } => {
let callee_ty = self.infer_expr(*callee, &Expectation::none());
let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone());
- let mut res = None;
- let mut derefed_callee = callee_ty.clone();
- // manual loop to be able to access `derefs.table`
- while let Some((callee_deref_ty, _)) = derefs.next() {
- res = derefs.table.callable_sig(&callee_deref_ty, args.len());
- if res.is_some() {
- derefed_callee = callee_deref_ty;
- break;
+ let (res, derefed_callee) = 'b: {
+ // manual loop to be able to access `derefs.table`
+ while let Some((callee_deref_ty, _)) = derefs.next() {
+ let res = derefs.table.callable_sig(&callee_deref_ty, args.len());
+ if res.is_some() {
+ break 'b (res, callee_deref_ty);
+ }
}
- }
+ (None, callee_ty.clone())
+ };
// if the function is unresolved, we use is_varargs=true to
// suppress the arg count diagnostic here
let is_varargs =
derefed_callee.callable_sig(self.db).map_or(false, |sig| sig.is_varargs)
|| res.is_none();
let (param_tys, ret_ty) = match res {
- Some(res) => {
+ Some((func, params, ret_ty)) => {
let adjustments = auto_deref_adjust_steps(&derefs);
// FIXME: Handle call adjustments for Fn/FnMut
self.write_expr_adj(*callee, adjustments);
- res
+ if let Some((trait_, func)) = func {
+ let subst = TyBuilder::subst_for_def(self.db, trait_, None)
+ .push(callee_ty.clone())
+ .push(TyBuilder::tuple_with(params.iter().cloned()))
+ .build();
+ self.write_method_resolution(tgt_expr, func, subst.clone());
+ }
+ (params, ret_ty)
}
None => (Vec::new(), self.err_ty()), // FIXME diagnostic
};
@@ -374,12 +384,9 @@ impl<'a> InferenceContext<'a> {
let expected = expected.adjust_for_branches(&mut self.table);
let result_ty = if arms.is_empty() {
- TyKind::Never.intern(Interner)
+ self.result.standard_types.never.clone()
} else {
- match &expected {
- Expectation::HasType(ty) => ty.clone(),
- _ => self.table.new_type_var(),
- }
+ expected.coercion_target_type(&mut self.table)
};
let mut coerce = CoerceMany::new(result_ty);
@@ -392,7 +399,7 @@ impl<'a> InferenceContext<'a> {
if let Some(guard_expr) = arm.guard {
self.infer_expr(
guard_expr,
- &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
+ &Expectation::HasType(self.result.standard_types.bool_.clone()),
);
}
@@ -417,7 +424,7 @@ impl<'a> InferenceContext<'a> {
is_break: false,
});
};
- TyKind::Never.intern(Interner)
+ self.result.standard_types.never.clone()
}
Expr::Break { expr, label } => {
let val_ty = if let Some(expr) = *expr {
@@ -431,7 +438,7 @@ impl<'a> InferenceContext<'a> {
// avoiding the borrowck
let mut coerce = mem::replace(
&mut ctxt.coerce,
- CoerceMany::new(self.result.standard_types.unknown.clone()),
+ CoerceMany::new(expected.coercion_target_type(&mut self.table)),
);
// FIXME: create a synthetic `()` during lowering so we have something to refer to here?
@@ -449,7 +456,7 @@ impl<'a> InferenceContext<'a> {
});
}
}
- TyKind::Never.intern(Interner)
+ self.result.standard_types.never.clone()
}
Expr::Return { expr } => {
if let Some(expr) = expr {
@@ -458,7 +465,7 @@ impl<'a> InferenceContext<'a> {
let unit = TyBuilder::unit();
let _ = self.coerce(Some(tgt_expr), &unit, &self.return_ty.clone());
}
- TyKind::Never.intern(Interner)
+ self.result.standard_types.never.clone()
}
Expr::Yield { expr } => {
if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
@@ -471,14 +478,14 @@ impl<'a> InferenceContext<'a> {
resume_ty
} else {
// FIXME: report error (yield expr in non-generator)
- TyKind::Error.intern(Interner)
+ self.result.standard_types.unknown.clone()
}
}
Expr::Yeet { expr } => {
if let &Some(expr) = expr {
self.infer_expr_inner(expr, &Expectation::None);
}
- TyKind::Never.intern(Interner)
+ self.result.standard_types.never.clone()
}
Expr::RecordLit { path, fields, spread, .. } => {
let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
@@ -588,12 +595,23 @@ impl<'a> InferenceContext<'a> {
}
Expr::Try { expr } => {
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
- self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
+ if let Some(trait_) = self.resolve_lang_trait(LangItem::Try) {
+ if let Some(func) = self.db.trait_data(trait_).method_by_name(&name!(branch)) {
+ let subst = TyBuilder::subst_for_def(self.db, trait_, None)
+ .push(inner_ty.clone())
+ .build();
+ self.write_method_resolution(tgt_expr, func, subst.clone());
+ }
+ let try_output = self.resolve_output_on(trait_);
+ self.resolve_associated_type(inner_ty, try_output)
+ } else {
+ self.err_ty()
+ }
}
Expr::Cast { expr, type_ref } => {
- // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
- let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
let cast_ty = self.make_ty(type_ref);
+ // FIXME: propagate the "castable to" expectation
+ let _inner_ty = self.infer_expr_inner(*expr, &Expectation::None);
// FIXME check the cast...
cast_ty
}
@@ -627,6 +645,7 @@ impl<'a> InferenceContext<'a> {
Expr::UnaryOp { expr, op } => {
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
let inner_ty = self.resolve_ty_shallow(&inner_ty);
+ // FIXME: Note down method resolution her
match op {
UnaryOp::Deref => {
autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty())
@@ -736,7 +755,7 @@ impl<'a> InferenceContext<'a> {
let base_ty = self.infer_expr_inner(*base, &Expectation::none());
let index_ty = self.infer_expr(*index, &Expectation::none());
- if let Some(index_trait) = self.resolve_ops_index() {
+ if let Some(index_trait) = self.resolve_lang_trait(LangItem::Index) {
let canonicalized = self.canonicalize(base_ty.clone());
let receiver_adjustments = method_resolution::resolve_indexing_op(
self.db,
@@ -749,6 +768,15 @@ impl<'a> InferenceContext<'a> {
adj.apply(&mut self.table, base_ty)
});
self.write_expr_adj(*base, adj);
+ if let Some(func) =
+ self.db.trait_data(index_trait).method_by_name(&name!(index))
+ {
+ let substs = TyBuilder::subst_for_def(self.db, index_trait, None)
+ .push(self_ty.clone())
+ .push(index_ty.clone())
+ .build();
+ self.write_method_resolution(tgt_expr, func, substs.clone());
+ }
self.resolve_associated_type_with_params(
self_ty,
self.resolve_ops_index_output(),
@@ -800,7 +828,7 @@ impl<'a> InferenceContext<'a> {
self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
self.infer_expr(
repeat,
- &Expectation::has_type(
+ &Expectation::HasType(
TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
),
);
@@ -823,7 +851,7 @@ impl<'a> InferenceContext<'a> {
TyKind::Array(coerce.complete(), len).intern(Interner)
}
Expr::Literal(lit) => match lit {
- Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
+ Literal::Bool(..) => self.result.standard_types.bool_.clone(),
Literal::String(..) => {
TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner))
.intern(Interner)
@@ -1009,7 +1037,7 @@ impl<'a> InferenceContext<'a> {
let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
let rhs_ty = self.table.new_type_var();
- let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
+ let trait_func = lang_items_for_bin_op(op).and_then(|(name, lang_item)| {
let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
let func = self.db.trait_data(trait_id).method_by_name(&name)?;
Some((trait_id, func))
@@ -1017,11 +1045,21 @@ impl<'a> InferenceContext<'a> {
let (trait_, func) = match trait_func {
Some(it) => it,
None => {
- let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
- let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
- return self
- .builtin_binary_op_return_ty(op, lhs_ty, rhs_ty)
- .unwrap_or_else(|| self.err_ty());
+ // HACK: `rhs_ty` is a general inference variable with no clue at all at this
+ // point. Passing `lhs_ty` as both operands just to check if `lhs_ty` is a builtin
+ // type applicable to `op`.
+ let ret_ty = if self.is_builtin_binop(&lhs_ty, &lhs_ty, op) {
+ // Assume both operands are builtin so we can continue inference. No guarantee
+ // on the correctness, rustc would complain as necessary lang items don't seem
+ // to exist anyway.
+ self.enforce_builtin_binop_types(&lhs_ty, &rhs_ty, op)
+ } else {
+ self.err_ty()
+ };
+
+ self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty));
+
+ return ret_ty;
}
};
@@ -1071,11 +1109,9 @@ impl<'a> InferenceContext<'a> {
let ret_ty = self.normalize_associated_types_in(ret_ty);
- // use knowledge of built-in binary ops, which can sometimes help inference
- if let Some(builtin_rhs) = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone()) {
- self.unify(&builtin_rhs, &rhs_ty);
- }
- if let Some(builtin_ret) = self.builtin_binary_op_return_ty(op, lhs_ty, rhs_ty) {
+ if self.is_builtin_binop(&lhs_ty, &rhs_ty, op) {
+ // use knowledge of built-in binary ops, which can sometimes help inference
+ let builtin_ret = self.enforce_builtin_binop_types(&lhs_ty, &rhs_ty, op);
self.unify(&builtin_ret, &ret_ty);
}
@@ -1111,7 +1147,7 @@ impl<'a> InferenceContext<'a> {
if let Some(expr) = else_branch {
self.infer_expr_coerce(
*expr,
- &Expectation::has_type(Ty::new(Interner, TyKind::Never)),
+ &Expectation::HasType(self.result.standard_types.never.clone()),
);
}
@@ -1136,18 +1172,16 @@ impl<'a> InferenceContext<'a> {
if self.diverges.is_always() {
// we don't even make an attempt at coercion
self.table.new_maybe_never_var()
- } else {
- if let Some(t) = expected.only_has_type(&mut self.table) {
- if self.coerce(Some(expr), &TyBuilder::unit(), &t).is_err() {
- self.result.type_mismatches.insert(
- expr.into(),
- TypeMismatch { expected: t.clone(), actual: TyBuilder::unit() },
- );
- }
- t
- } else {
- TyBuilder::unit()
+ } else if let Some(t) = expected.only_has_type(&mut self.table) {
+ if self.coerce(Some(expr), &TyBuilder::unit(), &t).is_err() {
+ self.result.type_mismatches.insert(
+ expr.into(),
+ TypeMismatch { expected: t.clone(), actual: TyBuilder::unit() },
+ );
}
+ t
+ } else {
+ TyBuilder::unit()
}
}
}
@@ -1271,7 +1305,7 @@ impl<'a> InferenceContext<'a> {
// that are not closures, then we type-check the closures. This is so
// that we have more information about the types of arguments when we
// type-check the functions. This isn't really the right way to do this.
- for &check_closures in &[false, true] {
+ for check_closures in [false, true] {
let mut skip_indices = skip_indices.into_iter().copied().fuse().peekable();
let param_iter = param_tys.iter().cloned().chain(repeat(self.err_ty()));
let expected_iter = expected_inputs
@@ -1314,13 +1348,13 @@ impl<'a> InferenceContext<'a> {
} else {
param_ty
};
- if !coercion_target.is_unknown() {
- if self.coerce(Some(arg), &ty, &coercion_target).is_err() {
- self.result.type_mismatches.insert(
- arg.into(),
- TypeMismatch { expected: coercion_target, actual: ty.clone() },
- );
- }
+ if !coercion_target.is_unknown()
+ && self.coerce(Some(arg), &ty, &coercion_target).is_err()
+ {
+ self.result.type_mismatches.insert(
+ arg.into(),
+ TypeMismatch { expected: coercion_target, actual: ty.clone() },
+ );
}
}
}
@@ -1479,92 +1513,124 @@ impl<'a> InferenceContext<'a> {
indices
}
- fn builtin_binary_op_return_ty(&mut self, op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Option<Ty> {
- let lhs_ty = self.resolve_ty_shallow(&lhs_ty);
- let rhs_ty = self.resolve_ty_shallow(&rhs_ty);
- match op {
- BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => {
- Some(TyKind::Scalar(Scalar::Bool).intern(Interner))
+ /// Dereferences a single level of immutable referencing.
+ fn deref_ty_if_possible(&mut self, ty: &Ty) -> Ty {
+ let ty = self.resolve_ty_shallow(ty);
+ match ty.kind(Interner) {
+ TyKind::Ref(Mutability::Not, _, inner) => self.resolve_ty_shallow(inner),
+ _ => ty,
+ }
+ }
+
+ /// Enforces expectations on lhs type and rhs type depending on the operator and returns the
+ /// output type of the binary op.
+ fn enforce_builtin_binop_types(&mut self, lhs: &Ty, rhs: &Ty, op: BinaryOp) -> Ty {
+ // Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work (See rust-lang/rust#57447).
+ let lhs = self.deref_ty_if_possible(lhs);
+ let rhs = self.deref_ty_if_possible(rhs);
+
+ let (op, is_assign) = match op {
+ BinaryOp::Assignment { op: Some(inner) } => (BinaryOp::ArithOp(inner), true),
+ _ => (op, false),
+ };
+
+ let output_ty = match op {
+ BinaryOp::LogicOp(_) => {
+ let bool_ = self.result.standard_types.bool_.clone();
+ self.unify(&lhs, &bool_);
+ self.unify(&rhs, &bool_);
+ bool_
}
- BinaryOp::Assignment { .. } => Some(TyBuilder::unit()),
+
BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => {
- // all integer combinations are valid here
- if matches!(
- lhs_ty.kind(Interner),
- TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
- | TyKind::InferenceVar(_, TyVariableKind::Integer)
- ) && matches!(
- rhs_ty.kind(Interner),
- TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
- | TyKind::InferenceVar(_, TyVariableKind::Integer)
- ) {
- Some(lhs_ty)
- } else {
- None
- }
+ // result type is same as LHS always
+ lhs
}
- BinaryOp::ArithOp(_) => match (lhs_ty.kind(Interner), rhs_ty.kind(Interner)) {
- // (int, int) | (uint, uint) | (float, float)
- (TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_)))
- | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
- | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => {
- Some(rhs_ty)
- }
- // ({int}, int) | ({int}, uint)
- (
- TyKind::InferenceVar(_, TyVariableKind::Integer),
- TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
- ) => Some(rhs_ty),
- // (int, {int}) | (uint, {int})
- (
- TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
- TyKind::InferenceVar(_, TyVariableKind::Integer),
- ) => Some(lhs_ty),
- // ({float} | float)
- (
- TyKind::InferenceVar(_, TyVariableKind::Float),
- TyKind::Scalar(Scalar::Float(_)),
- ) => Some(rhs_ty),
- // (float, {float})
- (
- TyKind::Scalar(Scalar::Float(_)),
- TyKind::InferenceVar(_, TyVariableKind::Float),
- ) => Some(lhs_ty),
- // ({int}, {int}) | ({float}, {float})
- (
- TyKind::InferenceVar(_, TyVariableKind::Integer),
- TyKind::InferenceVar(_, TyVariableKind::Integer),
- )
- | (
- TyKind::InferenceVar(_, TyVariableKind::Float),
- TyKind::InferenceVar(_, TyVariableKind::Float),
- ) => Some(rhs_ty),
- _ => None,
- },
+
+ BinaryOp::ArithOp(_) => {
+ // LHS, RHS, and result will have the same type
+ self.unify(&lhs, &rhs);
+ lhs
+ }
+
+ BinaryOp::CmpOp(_) => {
+ // LHS and RHS will have the same type
+ self.unify(&lhs, &rhs);
+ self.result.standard_types.bool_.clone()
+ }
+
+ BinaryOp::Assignment { op: None } => {
+ stdx::never!("Simple assignment operator is not binary op.");
+ lhs
+ }
+
+ BinaryOp::Assignment { .. } => unreachable!("handled above"),
+ };
+
+ if is_assign {
+ self.result.standard_types.unit.clone()
+ } else {
+ output_ty
}
}
- fn builtin_binary_op_rhs_expectation(&mut self, op: BinaryOp, lhs_ty: Ty) -> Option<Ty> {
- Some(match op {
- BinaryOp::LogicOp(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
- BinaryOp::Assignment { op: None } => lhs_ty,
- BinaryOp::CmpOp(CmpOp::Eq { .. }) => match self
- .resolve_ty_shallow(&lhs_ty)
- .kind(Interner)
- {
- TyKind::Scalar(_) | TyKind::Str => lhs_ty,
- TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
- _ => return None,
- },
- BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => return None,
- BinaryOp::CmpOp(CmpOp::Ord { .. })
- | BinaryOp::Assignment { op: Some(_) }
- | BinaryOp::ArithOp(_) => match self.resolve_ty_shallow(&lhs_ty).kind(Interner) {
- TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) => lhs_ty,
- TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
- _ => return None,
- },
- })
+ fn is_builtin_binop(&mut self, lhs: &Ty, rhs: &Ty, op: BinaryOp) -> bool {
+ // Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work (See rust-lang/rust#57447).
+ let lhs = self.deref_ty_if_possible(lhs);
+ let rhs = self.deref_ty_if_possible(rhs);
+
+ let op = match op {
+ BinaryOp::Assignment { op: Some(inner) } => BinaryOp::ArithOp(inner),
+ _ => op,
+ };
+
+ match op {
+ BinaryOp::LogicOp(_) => true,
+
+ BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => {
+ lhs.is_integral() && rhs.is_integral()
+ }
+
+ BinaryOp::ArithOp(
+ ArithOp::Add | ArithOp::Sub | ArithOp::Mul | ArithOp::Div | ArithOp::Rem,
+ ) => {
+ lhs.is_integral() && rhs.is_integral()
+ || lhs.is_floating_point() && rhs.is_floating_point()
+ }
+
+ BinaryOp::ArithOp(ArithOp::BitAnd | ArithOp::BitOr | ArithOp::BitXor) => {
+ lhs.is_integral() && rhs.is_integral()
+ || lhs.is_floating_point() && rhs.is_floating_point()
+ || matches!(
+ (lhs.kind(Interner), rhs.kind(Interner)),
+ (TyKind::Scalar(Scalar::Bool), TyKind::Scalar(Scalar::Bool))
+ )
+ }
+
+ BinaryOp::CmpOp(_) => {
+ let is_scalar = |kind| {
+ matches!(
+ kind,
+ &TyKind::Scalar(_)
+ | TyKind::FnDef(..)
+ | TyKind::Function(_)
+ | TyKind::Raw(..)
+ | TyKind::InferenceVar(
+ _,
+ TyVariableKind::Integer | TyVariableKind::Float
+ )
+ )
+ };
+ is_scalar(lhs.kind(Interner)) && is_scalar(rhs.kind(Interner))
+ }
+
+ BinaryOp::Assignment { op: None } => {
+ stdx::never!("Simple assignment operator is not binary op.");
+ false
+ }
+
+ BinaryOp::Assignment { .. } => unreachable!("handled above"),
+ }
}
fn with_breakable_ctx<T>(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index 8bd17c0f3..0a8527afb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -112,7 +112,7 @@ impl<'a> InferenceContext<'a> {
let ty = TyBuilder::value_ty(self.db, typable, parent_substs)
.fill(|x| {
it.next().unwrap_or_else(|| match x {
- ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
+ ParamKind::Type => self.result.standard_types.unknown.clone().cast(Interner),
ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
})
})
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index e7ddd1591..46ed3533c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -8,6 +8,7 @@ use chalk_ir::{
};
use chalk_solve::infer::ParameterEnaVariableExt;
use ena::unify::UnifyKey;
+use hir_def::{FunctionId, TraitId};
use hir_expand::name;
use stdx::never;
@@ -626,18 +627,26 @@ impl<'a> InferenceTable<'a> {
}
}
- pub(crate) fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
+ pub(crate) fn callable_sig(
+ &mut self,
+ ty: &Ty,
+ num_args: usize,
+ ) -> Option<(Option<(TraitId, FunctionId)>, Vec<Ty>, Ty)> {
match ty.callable_sig(self.db) {
- Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())),
+ Some(sig) => Some((None, sig.params().to_vec(), sig.ret().clone())),
None => self.callable_sig_from_fn_trait(ty, num_args),
}
}
- fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
+ fn callable_sig_from_fn_trait(
+ &mut self,
+ ty: &Ty,
+ num_args: usize,
+ ) -> Option<(Option<(TraitId, FunctionId)>, Vec<Ty>, Ty)> {
let krate = self.trait_env.krate;
let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?;
- let output_assoc_type =
- self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
+ let trait_data = self.db.trait_data(fn_once_trait);
+ let output_assoc_type = trait_data.associated_type_by_name(&name![Output])?;
let mut arg_tys = vec![];
let arg_ty = TyBuilder::tuple(num_args)
@@ -675,7 +684,11 @@ impl<'a> InferenceTable<'a> {
if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
self.register_obligation(obligation.goal);
let return_ty = self.normalize_projection_ty(projection);
- Some((arg_tys, return_ty))
+ Some((
+ Some(fn_once_trait).zip(trait_data.method_by_name(&name!(call_once))),
+ arg_tys,
+ return_ty,
+ ))
} else {
None
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs
index 441503a30..7bf73560c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs
@@ -4,11 +4,8 @@
use crate::{chalk_db, tls, GenericArg};
use base_db::salsa::InternId;
use chalk_ir::{Goal, GoalData};
-use hir_def::{
- intern::{impl_internable, InternStorage, Internable, Interned},
- type_ref::ConstScalar,
- TypeAliasId,
-};
+use hir_def::{type_ref::ConstScalar, TypeAliasId};
+use intern::{impl_internable, Interned};
use smallvec::SmallVec;
use std::{fmt, sync::Arc};
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs
index afc54e729..5308c7216 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs
@@ -1,20 +1,19 @@
//! Functions to detect special lang items
-use hir_def::{AdtId, HasModule};
-use hir_expand::name;
+use hir_def::{lang_item::LangItem, AdtId, HasModule};
use crate::db::HirDatabase;
pub fn is_box(adt: AdtId, db: &dyn HirDatabase) -> bool {
- let owned_box = name![owned_box].to_smol_str();
let krate = adt.module(db.upcast()).krate();
- let box_adt = db.lang_item(krate, owned_box).and_then(|it| it.as_struct()).map(AdtId::from);
+ let box_adt =
+ db.lang_item(krate, LangItem::OwnedBox).and_then(|it| it.as_struct()).map(AdtId::from);
Some(adt) == box_adt
}
pub fn is_unsafe_cell(adt: AdtId, db: &dyn HirDatabase) -> bool {
- let owned_box = name![unsafe_cell].to_smol_str();
let krate = adt.module(db.upcast()).krate();
- let box_adt = db.lang_item(krate, owned_box).and_then(|it| it.as_struct()).map(AdtId::from);
+ let box_adt =
+ db.lang_item(krate, LangItem::UnsafeCell).and_then(|it| it.as_struct()).map(AdtId::from);
Some(adt) == box_adt
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index 7a1cca314..f21b4f84c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -1,7 +1,5 @@
//! Compute the binary representation of a type
-use std::sync::Arc;
-
use base_db::CrateId;
use chalk_ir::{AdtId, TyKind};
use hir_def::{
@@ -31,19 +29,19 @@ mod adt;
mod target;
struct LayoutCx<'a> {
- db: &'a dyn HirDatabase,
krate: CrateId,
+ target: &'a TargetDataLayout,
}
-impl LayoutCalculator for LayoutCx<'_> {
- type TargetDataLayoutRef = Arc<TargetDataLayout>;
+impl<'a> LayoutCalculator for LayoutCx<'a> {
+ type TargetDataLayoutRef = &'a TargetDataLayout;
fn delay_bug(&self, txt: &str) {
never!("{}", txt);
}
- fn current_data_layout(&self) -> Arc<TargetDataLayout> {
- self.db.target_data_layout(self.krate)
+ fn current_data_layout(&self) -> &'a TargetDataLayout {
+ self.target
}
}
@@ -56,7 +54,8 @@ fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout {
}
pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Layout, LayoutError> {
- let cx = LayoutCx { db, krate };
+ let Some(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable) };
+ let cx = LayoutCx { krate, target: &target };
let dl = &*cx.current_data_layout();
Ok(match ty.kind(Interner) {
TyKind::Adt(AdtId(def), subst) => db.layout_of_adt(*def, subst.clone())?,
@@ -174,7 +173,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
// let pointee = tcx.normalize_erasing_regions(param_env, pointee);
// if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
- // return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
+ // return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
// }
let unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
@@ -226,10 +225,21 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
ptr.valid_range_mut().start = 1;
Layout::scalar(dl, ptr)
}
- TyKind::Closure(_, _)
- | TyKind::OpaqueType(_, _)
- | TyKind::Generator(_, _)
- | TyKind::GeneratorWitness(_, _) => return Err(LayoutError::NotImplemented),
+ TyKind::OpaqueType(opaque_ty_id, _) => {
+ let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
+ match impl_trait_id {
+ crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
+ let infer = db.infer(func.into());
+ layout_of_ty(db, &infer.type_of_rpit[idx], krate)?
+ }
+ crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
+ return Err(LayoutError::NotImplemented)
+ }
+ }
+ }
+ TyKind::Closure(_, _) | TyKind::Generator(_, _) | TyKind::GeneratorWitness(_, _) => {
+ return Err(LayoutError::NotImplemented)
+ }
TyKind::AssociatedType(_, _)
| TyKind::Error
| TyKind::Alias(_)
@@ -251,17 +261,14 @@ fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, La
fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {
match pointee.kind(Interner) {
- TyKind::Adt(AdtId(adt), subst) => match adt {
- &hir_def::AdtId::StructId(i) => {
- let data = db.struct_data(i);
- let mut it = data.variant_data.fields().iter().rev();
- match it.next() {
- Some((f, _)) => field_ty(db, i.into(), f, subst),
- None => pointee,
- }
+ TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), subst) => {
+ let data = db.struct_data(*i);
+ let mut it = data.variant_data.fields().iter().rev();
+ match it.next() {
+ Some((f, _)) => field_ty(db, (*i).into(), f, subst),
+ None => pointee,
}
- _ => pointee,
- },
+ }
_ => pointee,
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
index 23166a5a5..cb7968c14 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
@@ -23,7 +23,9 @@ pub fn layout_of_adt_query(
def: AdtId,
subst: Substitution,
) -> Result<Layout, LayoutError> {
- let cx = LayoutCx { db, krate: def.module(db.upcast()).krate() };
+ let krate = def.module(db.upcast()).krate();
+ let Some(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable) };
+ let cx = LayoutCx { krate, target: &target };
let dl = cx.current_data_layout();
let handle_variant = |def: VariantId, var: &VariantData| {
var.fields()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
index 37b831652..adfae0a1a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
@@ -3,34 +3,22 @@
use std::sync::Arc;
use base_db::CrateId;
-use hir_def::layout::{Endian, Size, TargetDataLayout};
+use hir_def::layout::TargetDataLayout;
use crate::db::HirDatabase;
-pub fn target_data_layout_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<TargetDataLayout> {
+pub fn target_data_layout_query(
+ db: &dyn HirDatabase,
+ krate: CrateId,
+) -> Option<Arc<TargetDataLayout>> {
let crate_graph = db.crate_graph();
- let target_layout = &crate_graph[krate].target_layout;
- let cfg_options = &crate_graph[krate].cfg_options;
- Arc::new(
- target_layout
- .as_ref()
- .and_then(|it| TargetDataLayout::parse_from_llvm_datalayout_string(it).ok())
- .unwrap_or_else(|| {
- let endian = match cfg_options.get_cfg_values("target_endian").next() {
- Some(x) if x.as_str() == "big" => Endian::Big,
- _ => Endian::Little,
- };
- let pointer_size = Size::from_bytes(
- match cfg_options.get_cfg_values("target_pointer_width").next() {
- Some(x) => match x.as_str() {
- "16" => 2,
- "32" => 4,
- _ => 8,
- },
- _ => 8,
- },
- );
- TargetDataLayout { endian, pointer_size, ..TargetDataLayout::default() }
- }),
- )
+ let target_layout = crate_graph[krate].target_layout.as_ref().ok()?;
+ let res = TargetDataLayout::parse_from_llvm_datalayout_string(&target_layout);
+ if let Err(_e) = &res {
+ // FIXME: Print the error here once it implements debug/display
+ // also logging here is somewhat wrong, but unfortunately this is the earliest place we can
+ // parse that doesn't impose a dependency to the rust-abi crate for project-model
+ tracing::error!("Failed to parse target data layout for {krate:?}");
+ }
+ res.ok().map(Arc::new)
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
index 53838cf41..067bdc960 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
@@ -1,3 +1,5 @@
+use std::collections::HashMap;
+
use base_db::fixture::WithFixture;
use chalk_ir::{AdtId, TyKind};
use hir_def::{
@@ -5,20 +7,16 @@ use hir_def::{
layout::{Layout, LayoutError},
};
-use crate::{test_db::TestDB, Interner, Substitution};
+use crate::{db::HirDatabase, test_db::TestDB, Interner, Substitution};
use super::layout_of_ty;
-fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> {
- // using unstable cargo features failed, fall back to using plain rustc
- let mut cmd = std::process::Command::new("rustc");
- cmd.args(["-Z", "unstable-options", "--print", "target-spec-json"]).env("RUSTC_BOOTSTRAP", "1");
- let output = cmd.output().unwrap();
- assert!(output.status.success(), "{}", output.status);
- let stdout = String::from_utf8(output.stdout).unwrap();
- let target_data_layout =
- stdout.split_once(r#""data-layout": ""#).unwrap().1.split_once('"').unwrap().0.to_owned();
+fn current_machine_data_layout() -> String {
+ project_model::target_data_layout::get(None, None, &HashMap::default()).unwrap()
+}
+fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> {
+ let target_data_layout = current_machine_data_layout();
let ra_fixture = format!(
"{minicore}//- /main.rs crate:test target_data_layout:{target_data_layout}\n{ra_fixture}",
);
@@ -45,6 +43,42 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> {
layout_of_ty(&db, &goal_ty, module_id.krate())
}
+/// A version of `eval_goal` for types that can not be expressed in ADTs, like closures and `impl Trait`
+fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> {
+ let target_data_layout = current_machine_data_layout();
+ let ra_fixture = format!(
+ "{minicore}//- /main.rs crate:test target_data_layout:{target_data_layout}\nfn main(){{let goal = {{{ra_fixture}}};}}",
+ );
+
+ let (db, file_id) = TestDB::with_single_file(&ra_fixture);
+ let module_id = db.module_for_file(file_id);
+ let def_map = module_id.def_map(&db);
+ let scope = &def_map[module_id.local_id].scope;
+ let adt_id = scope
+ .declarations()
+ .find_map(|x| match x {
+ hir_def::ModuleDefId::FunctionId(x) => {
+ let name = db.function_data(x).name.to_smol_str();
+ (name == "main").then_some(x)
+ }
+ _ => None,
+ })
+ .unwrap();
+ let hir_body = db.body(adt_id.into());
+ let pat = hir_body
+ .pats
+ .iter()
+ .find(|x| match x.1 {
+ hir_def::expr::Pat::Bind { name, .. } => name.to_smol_str() == "goal",
+ _ => false,
+ })
+ .unwrap()
+ .0;
+ let infer = db.infer(adt_id.into());
+ let goal_ty = infer.type_of_pat[pat].clone();
+ layout_of_ty(&db, &goal_ty, module_id.krate())
+}
+
#[track_caller]
fn check_size_and_align(ra_fixture: &str, minicore: &str, size: u64, align: u64) {
let l = eval_goal(ra_fixture, minicore).unwrap();
@@ -53,6 +87,13 @@ fn check_size_and_align(ra_fixture: &str, minicore: &str, size: u64, align: u64)
}
#[track_caller]
+fn check_size_and_align_expr(ra_fixture: &str, minicore: &str, size: u64, align: u64) {
+ let l = eval_expr(ra_fixture, minicore).unwrap();
+ assert_eq!(l.size.bytes(), size);
+ assert_eq!(l.align.abi.bytes(), align);
+}
+
+#[track_caller]
fn check_fail(ra_fixture: &str, e: LayoutError) {
let r = eval_goal(ra_fixture, "");
assert_eq!(r, Err(e));
@@ -85,11 +126,31 @@ macro_rules! size_and_align {
};
}
+macro_rules! size_and_align_expr {
+ ($($t:tt)*) => {
+ {
+ #[allow(dead_code)]
+ {
+ let val = { $($t)* };
+ check_size_and_align_expr(
+ stringify!($($t)*),
+ "",
+ ::std::mem::size_of_val(&val) as u64,
+ ::std::mem::align_of_val(&val) as u64,
+ );
+ }
+ }
+ };
+}
+
#[test]
fn hello_world() {
size_and_align! {
struct Goal(i32);
}
+ size_and_align_expr! {
+ 2i32
+ }
}
#[test]
@@ -144,6 +205,40 @@ fn generic() {
}
#[test]
+fn return_position_impl_trait() {
+ size_and_align_expr! {
+ trait T {}
+ impl T for i32 {}
+ impl T for i64 {}
+ fn foo() -> impl T { 2i64 }
+ foo()
+ }
+ size_and_align_expr! {
+ trait T {}
+ impl T for i32 {}
+ impl T for i64 {}
+ fn foo() -> (impl T, impl T, impl T) { (2i64, 5i32, 7i32) }
+ foo()
+ }
+ size_and_align_expr! {
+ struct Foo<T>(T, T, (T, T));
+ trait T {}
+ impl T for Foo<i32> {}
+ impl T for Foo<i64> {}
+
+ fn foo() -> Foo<impl T> { Foo(
+ Foo(1i64, 2, (3, 4)),
+ Foo(5, 6, (7, 8)),
+ (
+ Foo(1i64, 2, (3, 4)),
+ Foo(5, 6, (7, 8)),
+ ),
+ ) }
+ foo()
+ }
+}
+
+#[test]
fn enums() {
size_and_align! {
enum Goal {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index cbe6873c7..59a5ef8c1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -20,7 +20,6 @@ mod lower;
mod mapping;
mod tls;
mod utils;
-mod walk;
pub mod db;
pub mod diagnostics;
pub mod display;
@@ -40,11 +39,14 @@ use std::sync::Arc;
use chalk_ir::{
fold::{Shift, TypeFoldable},
interner::HasInterner,
- NoSolution,
+ visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
+ NoSolution, TyData,
};
use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
use hir_expand::name;
use itertools::Either;
+use la_arena::{Arena, Idx};
+use rustc_hash::FxHashSet;
use traits::FnTrait;
use utils::Generics;
@@ -71,7 +73,6 @@ pub use mapping::{
};
pub use traits::TraitEnvironment;
pub use utils::{all_super_traits, is_fn_unsafe_to_call};
-pub use walk::TypeWalk;
pub use chalk_ir::{
cast::Cast, AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind,
@@ -107,6 +108,7 @@ pub type GenericArgData = chalk_ir::GenericArgData<Interner>;
pub type Ty = chalk_ir::Ty<Interner>;
pub type TyKind = chalk_ir::TyKind<Interner>;
+pub type TypeFlags = chalk_ir::TypeFlags;
pub type DynTy = chalk_ir::DynTy<Interner>;
pub type FnPointer = chalk_ir::FnPointer<Interner>;
// pub type FnSubst = chalk_ir::FnSubst<Interner>;
@@ -289,22 +291,24 @@ impl TypeFoldable<Interner> for CallableSig {
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum ImplTraitId {
- ReturnTypeImplTrait(hir_def::FunctionId, u16),
+ ReturnTypeImplTrait(hir_def::FunctionId, RpitId),
AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct ReturnTypeImplTraits {
- pub(crate) impl_traits: Vec<ReturnTypeImplTrait>,
+ pub(crate) impl_traits: Arena<ReturnTypeImplTrait>,
}
has_interner!(ReturnTypeImplTraits);
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub(crate) struct ReturnTypeImplTrait {
+pub struct ReturnTypeImplTrait {
pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
}
+pub type RpitId = Idx<ReturnTypeImplTrait>;
+
pub fn static_lifetime() -> Lifetime {
LifetimeData::Static.intern(Interner)
}
@@ -563,3 +567,68 @@ pub fn callable_sig_from_fnonce(
Some(CallableSig::from_params_and_return(params, ret_ty, false, Safety::Safe))
}
+
+struct PlaceholderCollector<'db> {
+ db: &'db dyn HirDatabase,
+ placeholders: FxHashSet<TypeOrConstParamId>,
+}
+
+impl PlaceholderCollector<'_> {
+ fn collect(&mut self, idx: PlaceholderIndex) {
+ let id = from_placeholder_idx(self.db, idx);
+ self.placeholders.insert(id);
+ }
+}
+
+impl TypeVisitor<Interner> for PlaceholderCollector<'_> {
+ type BreakTy = ();
+
+ fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
+ self
+ }
+
+ fn interner(&self) -> Interner {
+ Interner
+ }
+
+ fn visit_ty(
+ &mut self,
+ ty: &Ty,
+ outer_binder: DebruijnIndex,
+ ) -> std::ops::ControlFlow<Self::BreakTy> {
+ let has_placeholder_bits = TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER;
+ let TyData { kind, flags } = ty.data(Interner);
+
+ if let TyKind::Placeholder(idx) = kind {
+ self.collect(*idx);
+ } else if flags.intersects(has_placeholder_bits) {
+ return ty.super_visit_with(self, outer_binder);
+ } else {
+ // Fast path: don't visit inner types (e.g. generic arguments) when `flags` indicate
+ // that there are no placeholders.
+ }
+
+ std::ops::ControlFlow::Continue(())
+ }
+
+ fn visit_const(
+ &mut self,
+ constant: &chalk_ir::Const<Interner>,
+ _outer_binder: DebruijnIndex,
+ ) -> std::ops::ControlFlow<Self::BreakTy> {
+ if let chalk_ir::ConstValue::Placeholder(idx) = constant.data(Interner).value {
+ self.collect(idx);
+ }
+ std::ops::ControlFlow::Continue(())
+ }
+}
+
+/// Returns unique placeholders for types and consts contained in `value`.
+pub fn collect_placeholders<T>(value: &T, db: &dyn HirDatabase) -> Vec<TypeOrConstParamId>
+where
+ T: ?Sized + TypeVisitable<Interner>,
+{
+ let mut collector = PlaceholderCollector { db, placeholders: FxHashSet::default() };
+ value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
+ collector.placeholders.into_iter().collect()
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 592410008..299646737 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -23,24 +23,24 @@ use hir_def::{
generics::{
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
},
- intern::Interned,
- lang_item::lang_attr,
+ lang_item::{lang_attr, LangItem},
path::{GenericArg, ModPath, Path, PathKind, PathSegment, PathSegments},
resolver::{HasResolver, Resolver, TypeNs},
type_ref::{
ConstScalarOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
},
AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
- HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
- TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId,
+ HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, StructId,
+ TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId,
};
use hir_expand::{name::Name, ExpandResult};
+use intern::Interned;
use itertools::Either;
-use la_arena::ArenaMap;
+use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashSet;
use smallvec::SmallVec;
use stdx::{impl_from, never};
-use syntax::{ast, SmolStr};
+use syntax::ast;
use crate::{
all_super_traits,
@@ -58,6 +58,51 @@ use crate::{
};
#[derive(Debug)]
+enum ImplTraitLoweringState {
+ /// When turning `impl Trait` into opaque types, we have to collect the
+ /// bounds at the same time to get the IDs correct (without becoming too
+ /// complicated). I don't like using interior mutability (as for the
+ /// counter), but I've tried and failed to make the lifetimes work for
+ /// passing around a `&mut TyLoweringContext`. The core problem is that
+ /// we're grouping the mutable data (the counter and this field) together
+ /// with the immutable context (the references to the DB and resolver).
+ /// Splitting this up would be a possible fix.
+ Opaque(RefCell<Arena<ReturnTypeImplTrait>>),
+ Param(Cell<u16>),
+ Variable(Cell<u16>),
+ Disallowed,
+}
+impl ImplTraitLoweringState {
+ fn new(impl_trait_mode: ImplTraitLoweringMode) -> ImplTraitLoweringState {
+ match impl_trait_mode {
+ ImplTraitLoweringMode::Opaque => Self::Opaque(RefCell::new(Arena::new())),
+ ImplTraitLoweringMode::Param => Self::Param(Cell::new(0)),
+ ImplTraitLoweringMode::Variable => Self::Variable(Cell::new(0)),
+ ImplTraitLoweringMode::Disallowed => Self::Disallowed,
+ }
+ }
+
+ fn take(&self) -> Self {
+ match self {
+ Self::Opaque(x) => Self::Opaque(RefCell::new(x.take())),
+ Self::Param(x) => Self::Param(Cell::new(x.get())),
+ Self::Variable(x) => Self::Variable(Cell::new(x.get())),
+ Self::Disallowed => Self::Disallowed,
+ }
+ }
+
+ fn swap(&self, impl_trait_mode: &Self) {
+ match (self, impl_trait_mode) {
+ (Self::Opaque(x), Self::Opaque(y)) => x.swap(y),
+ (Self::Param(x), Self::Param(y)) => x.swap(y),
+ (Self::Variable(x), Self::Variable(y)) => x.swap(y),
+ (Self::Disallowed, Self::Disallowed) => (),
+ _ => panic!("mismatched lowering mode"),
+ }
+ }
+}
+
+#[derive(Debug)]
pub struct TyLoweringContext<'a> {
pub db: &'a dyn HirDatabase,
pub resolver: &'a Resolver,
@@ -67,17 +112,7 @@ pub struct TyLoweringContext<'a> {
/// should be converted to variables. I think in practice, this isn't
/// possible currently, so this should be fine for now.
pub type_param_mode: ParamLoweringMode,
- pub impl_trait_mode: ImplTraitLoweringMode,
- impl_trait_counter: Cell<u16>,
- /// When turning `impl Trait` into opaque types, we have to collect the
- /// bounds at the same time to get the IDs correct (without becoming too
- /// complicated). I don't like using interior mutability (as for the
- /// counter), but I've tried and failed to make the lifetimes work for
- /// passing around a `&mut TyLoweringContext`. The core problem is that
- /// we're grouping the mutable data (the counter and this field) together
- /// with the immutable context (the references to the DB and resolver).
- /// Splitting this up would be a possible fix.
- opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
+ impl_trait_mode: ImplTraitLoweringState,
expander: RefCell<Option<Expander>>,
/// Tracks types with explicit `?Sized` bounds.
pub(crate) unsized_types: RefCell<FxHashSet<Ty>>,
@@ -85,19 +120,15 @@ pub struct TyLoweringContext<'a> {
impl<'a> TyLoweringContext<'a> {
pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
- let impl_trait_counter = Cell::new(0);
- let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
+ let impl_trait_mode = ImplTraitLoweringState::Disallowed;
let type_param_mode = ParamLoweringMode::Placeholder;
let in_binders = DebruijnIndex::INNERMOST;
- let opaque_type_data = RefCell::new(Vec::new());
Self {
db,
resolver,
in_binders,
impl_trait_mode,
- impl_trait_counter,
type_param_mode,
- opaque_type_data,
expander: RefCell::new(None),
unsized_types: RefCell::default(),
}
@@ -108,20 +139,18 @@ impl<'a> TyLoweringContext<'a> {
debruijn: DebruijnIndex,
f: impl FnOnce(&TyLoweringContext<'_>) -> T,
) -> T {
- let opaque_ty_data_vec = self.opaque_type_data.take();
+ let impl_trait_mode = self.impl_trait_mode.take();
let expander = self.expander.take();
let unsized_types = self.unsized_types.take();
let new_ctx = Self {
in_binders: debruijn,
- impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
- opaque_type_data: RefCell::new(opaque_ty_data_vec),
+ impl_trait_mode,
expander: RefCell::new(expander),
unsized_types: RefCell::new(unsized_types),
..*self
};
let result = f(&new_ctx);
- self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
- self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
+ self.impl_trait_mode.swap(&new_ctx.impl_trait_mode);
self.expander.replace(new_ctx.expander.into_inner());
self.unsized_types.replace(new_ctx.unsized_types.into_inner());
result
@@ -136,7 +165,7 @@ impl<'a> TyLoweringContext<'a> {
}
pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
- Self { impl_trait_mode, ..self }
+ Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self }
}
pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
@@ -244,20 +273,17 @@ impl<'a> TyLoweringContext<'a> {
}
TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
TypeRef::ImplTrait(bounds) => {
- match self.impl_trait_mode {
- ImplTraitLoweringMode::Opaque => {
- let idx = self.impl_trait_counter.get();
- self.impl_trait_counter.set(idx + 1);
+ match &self.impl_trait_mode {
+ ImplTraitLoweringState::Opaque(opaque_type_data) => {
let func = match self.resolver.generic_def() {
Some(GenericDefId::FunctionId(f)) => f,
_ => panic!("opaque impl trait lowering in non-function"),
};
- assert!(idx as usize == self.opaque_type_data.borrow().len());
// this dance is to make sure the data is in the right
// place even if we encounter more opaque types while
// lowering the bounds
- self.opaque_type_data.borrow_mut().push(ReturnTypeImplTrait {
+ let idx = opaque_type_data.borrow_mut().alloc(ReturnTypeImplTrait {
bounds: crate::make_single_type_binders(Vec::new()),
});
// We don't want to lower the bounds inside the binders
@@ -273,7 +299,7 @@ impl<'a> TyLoweringContext<'a> {
.with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
ctx.lower_impl_trait(bounds, func)
});
- self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data;
+ opaque_type_data.borrow_mut()[idx] = actual_opaque_type_data;
let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
@@ -281,10 +307,10 @@ impl<'a> TyLoweringContext<'a> {
let parameters = generics.bound_vars_subst(self.db, self.in_binders);
TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
}
- ImplTraitLoweringMode::Param => {
- let idx = self.impl_trait_counter.get();
+ ImplTraitLoweringState::Param(counter) => {
+ let idx = counter.get();
// FIXME we're probably doing something wrong here
- self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
+ counter.set(idx + count_impl_traits(type_ref) as u16);
if let Some(def) = self.resolver.generic_def() {
let generics = generics(self.db.upcast(), def);
let param = generics
@@ -305,10 +331,10 @@ impl<'a> TyLoweringContext<'a> {
TyKind::Error.intern(Interner)
}
}
- ImplTraitLoweringMode::Variable => {
- let idx = self.impl_trait_counter.get();
+ ImplTraitLoweringState::Variable(counter) => {
+ let idx = counter.get();
// FIXME we're probably doing something wrong here
- self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
+ counter.set(idx + count_impl_traits(type_ref) as u16);
let (
_parent_params,
self_params,
@@ -327,7 +353,7 @@ impl<'a> TyLoweringContext<'a> {
))
.intern(Interner)
}
- ImplTraitLoweringMode::Disallowed => {
+ ImplTraitLoweringState::Disallowed => {
// FIXME: report error
TyKind::Error.intern(Interner)
}
@@ -954,7 +980,7 @@ impl<'a> TyLoweringContext<'a> {
TypeBound::Path(path, TraitBoundModifier::Maybe) => {
let sized_trait = self
.db
- .lang_item(self.resolver.krate(), SmolStr::new_inline("sized"))
+ .lang_item(self.resolver.krate(), LangItem::Sized)
.and_then(|lang_item| lang_item.as_trait());
// Don't lower associated type bindings as the only possible relaxed trait bound
// `?Sized` has no of them.
@@ -999,7 +1025,7 @@ impl<'a> TyLoweringContext<'a> {
last_segment
.into_iter()
.filter_map(|segment| segment.args_and_bindings)
- .flat_map(|args_and_bindings| &args_and_bindings.bindings)
+ .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
.flat_map(move |binding| {
let found = associated_type_by_name_including_super_traits(
self.db,
@@ -1042,7 +1068,7 @@ impl<'a> TyLoweringContext<'a> {
AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
preds.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
}
- for bound in &binding.bounds {
+ for bound in binding.bounds.iter() {
preds.extend(self.lower_type_bound(
bound,
TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner),
@@ -1150,7 +1176,7 @@ impl<'a> TyLoweringContext<'a> {
let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
let sized_trait = ctx
.db
- .lang_item(krate, SmolStr::new_inline("sized"))
+ .lang_item(krate, LangItem::Sized)
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
let sized_clause = sized_trait.map(|trait_id| {
let clause = WhereClause::Implemented(TraitRef {
@@ -1209,7 +1235,7 @@ fn named_associated_type_shorthand_candidates<R>(
mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
) -> Option<R> {
let mut search = |t| {
- for t in all_super_trait_refs(db, t) {
+ all_super_trait_refs(db, t, |t| {
let data = db.trait_data(t.hir_trait_id());
for (name, assoc_id) in &data.items {
@@ -1219,8 +1245,8 @@ fn named_associated_type_shorthand_candidates<R>(
}
}
}
- }
- None
+ None
+ })
};
match res {
@@ -1489,7 +1515,7 @@ fn implicitly_sized_clauses<'a>(
let is_trait_def = matches!(def, GenericDefId::TraitId(..));
let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..];
let sized_trait = db
- .lang_item(resolver.krate(), SmolStr::new_inline("sized"))
+ .lang_item(resolver.krate(), LangItem::Sized)
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
sized_trait.into_iter().flat_map(move |sized_trait| {
@@ -1704,6 +1730,15 @@ pub enum CallableDefId {
EnumVariantId(EnumVariantId),
}
impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
+impl From<CallableDefId> for ModuleDefId {
+ fn from(def: CallableDefId) -> ModuleDefId {
+ match def {
+ CallableDefId::FunctionId(f) => ModuleDefId::FunctionId(f),
+ CallableDefId::StructId(s) => ModuleDefId::AdtId(AdtId::StructId(s)),
+ CallableDefId::EnumVariantId(e) => ModuleDefId::EnumVariantId(e),
+ }
+ }
+}
impl CallableDefId {
pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
@@ -1854,8 +1889,12 @@ pub(crate) fn return_type_impl_traits(
.with_type_param_mode(ParamLoweringMode::Variable);
let _ret = ctx_ret.lower_ty(&data.ret_type);
let generics = generics(db.upcast(), def.into());
- let return_type_impl_traits =
- ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() };
+ let return_type_impl_traits = ReturnTypeImplTraits {
+ impl_traits: match ctx_ret.impl_trait_mode {
+ ImplTraitLoweringState::Opaque(x) => x.into_inner(),
+ _ => unreachable!(),
+ },
+ };
if return_type_impl_traits.impl_traits.is_empty() {
None
} else {
@@ -1931,7 +1970,7 @@ pub(crate) fn const_or_path_to_chalk(
debruijn: DebruijnIndex,
) -> Const {
match value {
- ConstScalarOrPath::Scalar(s) => intern_const_scalar(s.clone(), expected_ty),
+ ConstScalarOrPath::Scalar(s) => intern_const_scalar(*s, expected_ty),
ConstScalarOrPath::Path(n) => {
let path = ModPath::from_segments(PathKind::Plain, Some(n.clone()));
path_to_const(db, resolver, &path, mode, args, debruijn)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 2328dceb8..8c7714b9a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -5,10 +5,11 @@
use std::{ops::ControlFlow, sync::Arc};
use base_db::{CrateId, Edition};
-use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
+use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex};
use hir_def::{
- data::ImplData, item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId,
- FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
+ data::ImplData, item_scope::ItemScope, lang_item::LangItem, nameres::DefMap, AssocItemId,
+ BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
+ ModuleId, TraitId,
};
use hir_expand::name::Name;
use rustc_hash::{FxHashMap, FxHashSet};
@@ -24,7 +25,7 @@ use crate::{
static_lifetime, to_chalk_trait_id,
utils::all_super_traits,
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
- Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
+ Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
};
/// This is used as a key for indexing impls.
@@ -437,49 +438,49 @@ pub fn def_crates(
}
}
-pub fn lang_names_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, Name)> {
+pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> {
use hir_expand::name;
use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering};
Some(match op {
BinaryOp::LogicOp(_) => return None,
BinaryOp::ArithOp(aop) => match aop {
- ArithOp::Add => (name!(add), name!(add)),
- ArithOp::Mul => (name!(mul), name!(mul)),
- ArithOp::Sub => (name!(sub), name!(sub)),
- ArithOp::Div => (name!(div), name!(div)),
- ArithOp::Rem => (name!(rem), name!(rem)),
- ArithOp::Shl => (name!(shl), name!(shl)),
- ArithOp::Shr => (name!(shr), name!(shr)),
- ArithOp::BitXor => (name!(bitxor), name!(bitxor)),
- ArithOp::BitOr => (name!(bitor), name!(bitor)),
- ArithOp::BitAnd => (name!(bitand), name!(bitand)),
+ ArithOp::Add => (name![add], LangItem::Add),
+ ArithOp::Mul => (name![mul], LangItem::Mul),
+ ArithOp::Sub => (name![sub], LangItem::Sub),
+ ArithOp::Div => (name![div], LangItem::Div),
+ ArithOp::Rem => (name![rem], LangItem::Rem),
+ ArithOp::Shl => (name![shl], LangItem::Shl),
+ ArithOp::Shr => (name![shr], LangItem::Shr),
+ ArithOp::BitXor => (name![bitxor], LangItem::BitXor),
+ ArithOp::BitOr => (name![bitor], LangItem::BitOr),
+ ArithOp::BitAnd => (name![bitand], LangItem::BitAnd),
},
BinaryOp::Assignment { op: Some(aop) } => match aop {
- ArithOp::Add => (name!(add_assign), name!(add_assign)),
- ArithOp::Mul => (name!(mul_assign), name!(mul_assign)),
- ArithOp::Sub => (name!(sub_assign), name!(sub_assign)),
- ArithOp::Div => (name!(div_assign), name!(div_assign)),
- ArithOp::Rem => (name!(rem_assign), name!(rem_assign)),
- ArithOp::Shl => (name!(shl_assign), name!(shl_assign)),
- ArithOp::Shr => (name!(shr_assign), name!(shr_assign)),
- ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)),
- ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)),
- ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)),
+ ArithOp::Add => (name![add_assign], LangItem::AddAssign),
+ ArithOp::Mul => (name![mul_assign], LangItem::MulAssign),
+ ArithOp::Sub => (name![sub_assign], LangItem::SubAssign),
+ ArithOp::Div => (name![div_assign], LangItem::DivAssign),
+ ArithOp::Rem => (name![rem_assign], LangItem::RemAssign),
+ ArithOp::Shl => (name![shl_assign], LangItem::ShlAssign),
+ ArithOp::Shr => (name![shr_assign], LangItem::ShrAssign),
+ ArithOp::BitXor => (name![bitxor_assign], LangItem::BitXorAssign),
+ ArithOp::BitOr => (name![bitor_assign], LangItem::BitOrAssign),
+ ArithOp::BitAnd => (name![bitand_assign], LangItem::BitAndAssign),
},
BinaryOp::CmpOp(cop) => match cop {
- CmpOp::Eq { negated: false } => (name!(eq), name!(eq)),
- CmpOp::Eq { negated: true } => (name!(ne), name!(eq)),
+ CmpOp::Eq { negated: false } => (name![eq], LangItem::PartialEq),
+ CmpOp::Eq { negated: true } => (name![ne], LangItem::PartialEq),
CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
- (name!(le), name!(partial_ord))
+ (name![le], LangItem::PartialOrd)
}
CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
- (name!(lt), name!(partial_ord))
+ (name![lt], LangItem::PartialOrd)
}
CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
- (name!(ge), name!(partial_ord))
+ (name![ge], LangItem::PartialOrd)
}
CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
- (name!(gt), name!(partial_ord))
+ (name![gt], LangItem::PartialOrd)
}
},
BinaryOp::Assignment { op: None } => return None,
@@ -587,25 +588,31 @@ impl ReceiverAdjustments {
}
}
}
+ if let Some(m) = self.autoref {
+ ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner);
+ adjust
+ .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() });
+ }
if self.unsize_array {
- ty = match ty.kind(Interner) {
- TyKind::Array(inner, _) => TyKind::Slice(inner.clone()).intern(Interner),
- _ => {
- never!("unsize_array with non-array {:?}", ty);
- ty
+ ty = 'x: {
+ if let TyKind::Ref(m, l, inner) = ty.kind(Interner) {
+ if let TyKind::Array(inner, _) = inner.kind(Interner) {
+ break 'x TyKind::Ref(
+ m.clone(),
+ l.clone(),
+ TyKind::Slice(inner.clone()).intern(Interner),
+ )
+ .intern(Interner);
+ }
}
+ never!("unsize_array with non-reference-to-array {:?}", ty);
+ ty
};
- // FIXME this is kind of wrong since the unsize needs to happen to a pointer/reference
adjust.push(Adjustment {
kind: Adjust::Pointer(PointerCast::Unsize),
target: ty.clone(),
});
}
- if let Some(m) = self.autoref {
- ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner);
- adjust
- .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() });
- }
(ty, adjust)
}
@@ -712,17 +719,17 @@ fn lookup_impl_assoc_item_for_trait_ref(
let table = InferenceTable::new(db, env);
let impl_data = find_matching_impl(impls, table, trait_ref)?;
- impl_data.items.iter().find_map(|it| match it {
+ impl_data.items.iter().find_map(|&it| match it {
AssocItemId::FunctionId(f) => {
- (db.function_data(*f).name == *name).then_some(AssocItemId::FunctionId(*f))
+ (db.function_data(f).name == *name).then_some(AssocItemId::FunctionId(f))
}
AssocItemId::ConstId(c) => db
- .const_data(*c)
+ .const_data(c)
.name
.as_ref()
- .map(|n| *n == *name)
- .and_then(|result| if result { Some(AssocItemId::ConstId(*c)) } else { None }),
- _ => None,
+ .map(|n| n == name)
+ .and_then(|result| if result { Some(AssocItemId::ConstId(c)) } else { None }),
+ AssocItemId::TypeAliasId(_) => None,
})
}
@@ -1094,13 +1101,13 @@ fn iterate_inherent_methods(
None => return ControlFlow::Continue(()),
};
- let (module, block) = match visible_from_module {
+ let (module, mut block) = match visible_from_module {
VisibleFromModule::Filter(module) => (Some(module), module.containing_block()),
VisibleFromModule::IncludeBlock(block) => (None, Some(block)),
VisibleFromModule::None => (None, None),
};
- if let Some(block_id) = block {
+ while let Some(block_id) = block {
if let Some(impls) = db.inherent_impls_in_block(block_id) {
impls_for_self_ty(
&impls,
@@ -1113,6 +1120,11 @@ fn iterate_inherent_methods(
callback,
)?;
}
+
+ block = db
+ .block_def_map(block_id)
+ .and_then(|map| map.parent())
+ .and_then(|module| module.containing_block());
}
for krate in def_crates {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index 6c7a53299..41c53701d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -813,7 +813,7 @@ fn test() {
fn method_resolution_trait_from_prelude() {
check_types(
r#"
-//- /main.rs crate:main deps:core
+//- /main.rs edition:2018 crate:main deps:core
struct S;
impl Clone for S {}
@@ -986,14 +986,13 @@ fn main() {
}
#[test]
-fn method_resolution_encountering_fn_type() {
+fn explicit_fn_once_call_fn_item() {
check_types(
r#"
-//- /main.rs
+//- minicore: fn
fn foo() {}
-trait FnOnce { fn call(self); }
-fn test() { foo.call(); }
- //^^^^^^^^^^ {unknown}
+fn test() { foo.call_once(); }
+ //^^^^^^^^^^^^^^^ ()
"#,
);
}
@@ -1527,7 +1526,7 @@ fn f(x: U2) {
fn skip_array_during_method_dispatch() {
check_types(
r#"
-//- /main2018.rs crate:main2018 deps:core
+//- /main2018.rs crate:main2018 deps:core edition:2018
use core::IntoIterator;
fn f() {
@@ -1725,14 +1724,13 @@ fn test() {
#[test]
fn receiver_adjustment_unsize_array() {
- // FIXME not quite correct
check(
r#"
//- minicore: slice
fn test() {
let a = [1, 2, 3];
a.len();
-} //^ adjustments: Pointer(Unsize), Borrow(Ref(Not))
+} //^ adjustments: Borrow(Ref(Not)), Pointer(Unsize)
"#,
);
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index 146145523..2e5787b70 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -3200,3 +3200,86 @@ fn func() {
"#,
);
}
+
+// FIXME
+#[test]
+fn castable_to() {
+ check_infer(
+ r#"
+//- minicore: sized
+#[lang = "owned_box"]
+pub struct Box<T: ?Sized> {
+ inner: *mut T,
+}
+impl<T> Box<T> {
+ fn new(t: T) -> Self { loop {} }
+}
+
+fn func() {
+ let x = Box::new([]) as Box<[i32; 0]>;
+}
+"#,
+ expect![[r#"
+ 99..100 't': T
+ 113..124 '{ loop {} }': Box<T>
+ 115..122 'loop {}': !
+ 120..122 '{}': ()
+ 138..184 '{ ...0]>; }': ()
+ 148..149 'x': Box<[i32; 0]>
+ 152..160 'Box::new': fn new<[{unknown}; 0]>([{unknown}; 0]) -> Box<[{unknown}; 0]>
+ 152..164 'Box::new([])': Box<[{unknown}; 0]>
+ 152..181 'Box::n...2; 0]>': Box<[i32; 0]>
+ 161..163 '[]': [{unknown}; 0]
+ "#]],
+ );
+}
+
+#[test]
+fn castable_to1() {
+ check_infer(
+ r#"
+struct Ark<T>(T);
+impl<T> Ark<T> {
+ fn foo(&self) -> *const T {
+ &self.0
+ }
+}
+fn f<T>(t: Ark<T>) {
+ Ark::foo(&t) as *const ();
+}
+"#,
+ expect![[r#"
+ 47..51 'self': &Ark<T>
+ 65..88 '{ ... }': *const T
+ 75..82 '&self.0': &T
+ 76..80 'self': &Ark<T>
+ 76..82 'self.0': T
+ 99..100 't': Ark<T>
+ 110..144 '{ ... (); }': ()
+ 116..124 'Ark::foo': fn foo<T>(&Ark<T>) -> *const T
+ 116..128 'Ark::foo(&t)': *const T
+ 116..141 'Ark::f...nst ()': *const ()
+ 125..127 '&t': &Ark<T>
+ 126..127 't': Ark<T>
+ "#]],
+ );
+}
+
+// FIXME
+#[test]
+fn castable_to2() {
+ check_infer(
+ r#"
+fn func() {
+ let x = &0u32 as *const _;
+}
+"#,
+ expect![[r#"
+ 10..44 '{ ...t _; }': ()
+ 20..21 'x': *const {unknown}
+ 24..29 '&0u32': &u32
+ 24..41 '&0u32 ...onst _': *const {unknown}
+ 25..29 '0u32': u32
+ "#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index d01fe0632..015085bde 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -163,98 +163,22 @@ fn test() {
}
#[test]
-fn infer_try() {
+fn infer_try_trait() {
check_types(
r#"
-//- /main.rs crate:main deps:core
+//- minicore: try, result
fn test() {
let r: Result<i32, u64> = Result::Ok(1);
let v = r?;
v;
} //^ i32
-//- /core.rs crate:core
-pub mod ops {
- pub trait Try {
- type Ok;
- type Error;
- }
-}
-
-pub mod result {
- pub enum Result<O, E> {
- Ok(O),
- Err(E)
- }
-
- impl<O, E> crate::ops::Try for Result<O, E> {
- type Ok = O;
- type Error = E;
- }
-}
-
-pub mod prelude {
- pub mod rust_2018 {
- pub use crate::{result::*, ops::*};
- }
-}
-"#,
- );
-}
-
-#[test]
-fn infer_try_trait_v2() {
- check_types(
- r#"
-//- /main.rs crate:main deps:core
-fn test() {
- let r: Result<i32, u64> = Result::Ok(1);
- let v = r?;
- v;
-} //^ i32
-
-//- /core.rs crate:core
-mod ops {
- mod try_trait {
- pub trait Try: FromResidual {
- type Output;
- type Residual;
- }
- pub trait FromResidual<R = <Self as Try>::Residual> {}
- }
-
- pub use self::try_trait::FromResidual;
- pub use self::try_trait::Try;
+impl<O, E> core::ops::Try for Result<O, E> {
+ type Output = O;
+ type Error = Result<core::convert::Infallible, E>;
}
-mod convert {
- pub trait From<T> {}
- impl<T> From<T> for T {}
-}
-
-pub mod result {
- use crate::convert::From;
- use crate::ops::{Try, FromResidual};
-
- pub enum Infallible {}
- pub enum Result<O, E> {
- Ok(O),
- Err(E)
- }
-
- impl<O, E> Try for Result<O, E> {
- type Output = O;
- type Error = Result<Infallible, E>;
- }
-
- impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {}
-}
-
-pub mod prelude {
- pub mod rust_2018 {
- pub use crate::result::*;
- }
-}
+impl<T, E, F: From<E>> core::ops::FromResidual<Result<core::convert::Infallible, E>> for Result<T, F> {}
"#,
);
}
@@ -263,7 +187,8 @@ pub mod prelude {
fn infer_for_loop() {
check_types(
r#"
-//- /main.rs crate:main deps:core,alloc
+//- minicore: iterator
+//- /main.rs crate:main deps:alloc
#![no_std]
use alloc::collections::Vec;
@@ -275,23 +200,7 @@ fn test() {
} //^ &str
}
-//- /core.rs crate:core
-pub mod iter {
- pub trait IntoIterator {
- type Item;
- type IntoIter: Iterator<Item = Self::Item>;
- }
- pub trait Iterator {
- type Item;
- }
-}
-pub mod prelude {
- pub mod rust_2018 {
- pub use crate::iter::*;
- }
-}
-
-//- /alloc.rs crate:alloc deps:core
+//- /alloc.rs crate:alloc
#![no_std]
pub mod collections {
pub struct Vec<T> {}
@@ -1848,25 +1757,19 @@ fn test() {
fn fn_trait() {
check_infer_with_mismatches(
r#"
-trait FnOnce<Args> {
- type Output;
-
- fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
-}
+//- minicore: fn
fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
f.call_once((1, 2));
}"#,
expect![[r#"
- 56..60 'self': Self
- 62..66 'args': Args
- 149..150 'f': F
- 155..183 '{ ...2)); }': ()
- 161..162 'f': F
- 161..180 'f.call...1, 2))': u128
- 173..179 '(1, 2)': (u32, u64)
- 174..175 '1': u32
- 177..178 '2': u64
+ 38..39 'f': F
+ 44..72 '{ ...2)); }': ()
+ 50..51 'f': F
+ 50..69 'f.call...1, 2))': u128
+ 62..68 '(1, 2)': (u32, u64)
+ 63..64 '1': u32
+ 66..67 '2': u64
"#]],
);
}
@@ -1875,12 +1778,7 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
fn fn_ptr_and_item() {
check_infer_with_mismatches(
r#"
-#[lang="fn_once"]
-trait FnOnce<Args> {
- type Output;
-
- fn call_once(self, args: Args) -> Self::Output;
-}
+//- minicore: fn
trait Foo<T> {
fn foo(&self) -> T;
@@ -1906,27 +1804,25 @@ fn test() {
opt.map(f);
}"#,
expect![[r#"
- 74..78 'self': Self
- 80..84 'args': Args
- 139..143 'self': &Self
- 243..247 'self': &Bar<F>
- 260..271 '{ loop {} }': (A1, R)
- 262..269 'loop {}': !
- 267..269 '{}': ()
- 355..359 'self': Opt<T>
- 361..362 'f': F
- 377..388 '{ loop {} }': Opt<U>
- 379..386 'loop {}': !
- 384..386 '{}': ()
- 402..518 '{ ...(f); }': ()
- 412..415 'bar': Bar<fn(u8) -> u32>
- 441..444 'bar': Bar<fn(u8) -> u32>
- 441..450 'bar.foo()': (u8, u32)
- 461..464 'opt': Opt<u8>
- 483..484 'f': fn(u8) -> u32
- 505..508 'opt': Opt<u8>
- 505..515 'opt.map(f)': Opt<u32>
- 513..514 'f': fn(u8) -> u32
+ 28..32 'self': &Self
+ 132..136 'self': &Bar<F>
+ 149..160 '{ loop {} }': (A1, R)
+ 151..158 'loop {}': !
+ 156..158 '{}': ()
+ 244..248 'self': Opt<T>
+ 250..251 'f': F
+ 266..277 '{ loop {} }': Opt<U>
+ 268..275 'loop {}': !
+ 273..275 '{}': ()
+ 291..407 '{ ...(f); }': ()
+ 301..304 'bar': Bar<fn(u8) -> u32>
+ 330..333 'bar': Bar<fn(u8) -> u32>
+ 330..339 'bar.foo()': (u8, u32)
+ 350..353 'opt': Opt<u8>
+ 372..373 'f': fn(u8) -> u32
+ 394..397 'opt': Opt<u8>
+ 394..404 'opt.map(f)': Opt<u32>
+ 402..403 'f': fn(u8) -> u32
"#]],
);
}
@@ -2399,10 +2295,8 @@ fn unselected_projection_in_trait_env_no_cycle() {
// this is not a cycle
check_types(
r#"
-//- /main.rs
-trait Index {
- type Output;
-}
+//- minicore: index
+use core::ops::Index;
type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key;
@@ -2999,40 +2893,17 @@ fn test() {
fn integer_range_iterate() {
check_types(
r#"
-//- /main.rs crate:main deps:core
+//- minicore: range, iterator
+//- /main.rs crate:main
fn test() {
for x in 0..100 { x; }
} //^ i32
-//- /core.rs crate:core
-pub mod ops {
- pub struct Range<Idx> {
- pub start: Idx,
- pub end: Idx,
- }
-}
-
-pub mod iter {
- pub trait Iterator {
- type Item;
- }
-
- pub trait IntoIterator {
- type Item;
- type IntoIter: Iterator<Item = Self::Item>;
- }
-
- impl<T> IntoIterator for T where T: Iterator {
- type Item = <T as Iterator>::Item;
- type IntoIter = Self;
- }
-}
-
trait Step {}
impl Step for i32 {}
impl Step for i64 {}
-impl<A: Step> iter::Iterator for ops::Range<A> {
+impl<A: Step> core::iter::Iterator for core::ops::Range<A> {
type Item = A;
}
"#,
@@ -3507,14 +3378,9 @@ trait Request {
fn bin_op_adt_with_rhs_primitive() {
check_infer_with_mismatches(
r#"
-#[lang = "add"]
-pub trait Add<Rhs = Self> {
- type Output;
- fn add(self, rhs: Rhs) -> Self::Output;
-}
-
+//- minicore: add
struct Wrapper(u32);
-impl Add<u32> for Wrapper {
+impl core::ops::Add<u32> for Wrapper {
type Output = Self;
fn add(self, rhs: u32) -> Wrapper {
Wrapper(rhs)
@@ -3527,30 +3393,107 @@ fn main(){
}"#,
expect![[r#"
- 72..76 'self': Self
- 78..81 'rhs': Rhs
- 192..196 'self': Wrapper
- 198..201 'rhs': u32
- 219..247 '{ ... }': Wrapper
- 229..236 'Wrapper': Wrapper(u32) -> Wrapper
- 229..241 'Wrapper(rhs)': Wrapper
- 237..240 'rhs': u32
- 259..345 '{ ...um; }': ()
- 269..276 'wrapped': Wrapper
- 279..286 'Wrapper': Wrapper(u32) -> Wrapper
- 279..290 'Wrapper(10)': Wrapper
- 287..289 '10': u32
- 300..303 'num': u32
- 311..312 '2': u32
- 322..325 'res': Wrapper
- 328..335 'wrapped': Wrapper
- 328..341 'wrapped + num': Wrapper
- 338..341 'num': u32
+ 95..99 'self': Wrapper
+ 101..104 'rhs': u32
+ 122..150 '{ ... }': Wrapper
+ 132..139 'Wrapper': Wrapper(u32) -> Wrapper
+ 132..144 'Wrapper(rhs)': Wrapper
+ 140..143 'rhs': u32
+ 162..248 '{ ...um; }': ()
+ 172..179 'wrapped': Wrapper
+ 182..189 'Wrapper': Wrapper(u32) -> Wrapper
+ 182..193 'Wrapper(10)': Wrapper
+ 190..192 '10': u32
+ 203..206 'num': u32
+ 214..215 '2': u32
+ 225..228 'res': Wrapper
+ 231..238 'wrapped': Wrapper
+ 231..244 'wrapped + num': Wrapper
+ 241..244 'num': u32
"#]],
)
}
#[test]
+fn builtin_binop_expectation_works_on_single_reference() {
+ check_types(
+ r#"
+//- minicore: add
+use core::ops::Add;
+impl Add<i32> for i32 { type Output = i32 }
+impl Add<&i32> for i32 { type Output = i32 }
+impl Add<u32> for u32 { type Output = u32 }
+impl Add<&u32> for u32 { type Output = u32 }
+
+struct V<T>;
+impl<T> V<T> {
+ fn default() -> Self { loop {} }
+ fn get(&self, _: &T) -> &T { loop {} }
+}
+
+fn take_u32(_: u32) {}
+fn minimized() {
+ let v = V::default();
+ let p = v.get(&0);
+ //^ &u32
+ take_u32(42 + p);
+}
+"#,
+ );
+}
+
+#[test]
+fn no_builtin_binop_expectation_for_general_ty_var() {
+ // FIXME: Ideally type mismatch should be reported on `take_u32(42 - p)`.
+ check_types(
+ r#"
+//- minicore: add
+use core::ops::Add;
+impl Add<i32> for i32 { type Output = i32; }
+impl Add<&i32> for i32 { type Output = i32; }
+// This is needed to prevent chalk from giving unique solution to `i32: Add<&?0>` after applying
+// fallback to integer type variable for `42`.
+impl Add<&()> for i32 { type Output = (); }
+
+struct V<T>;
+impl<T> V<T> {
+ fn default() -> Self { loop {} }
+ fn get(&self) -> &T { loop {} }
+}
+
+fn take_u32(_: u32) {}
+fn minimized() {
+ let v = V::default();
+ let p = v.get();
+ //^ &{unknown}
+ take_u32(42 + p);
+}
+"#,
+ );
+}
+
+#[test]
+fn no_builtin_binop_expectation_for_non_builtin_types() {
+ check_no_mismatches(
+ r#"
+//- minicore: default, eq
+struct S;
+impl Default for S { fn default() -> Self { S } }
+impl Default for i32 { fn default() -> Self { 0 } }
+impl PartialEq<S> for i32 { fn eq(&self, _: &S) -> bool { true } }
+impl PartialEq<i32> for i32 { fn eq(&self, _: &S) -> bool { true } }
+
+fn take_s(_: S) {}
+fn test() {
+ let s = Default::default();
+ let _eq = 0 == s;
+ take_s(s);
+}
+"#,
+ )
+}
+
+#[test]
fn array_length() {
check_infer(
r#"
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
index 778a6b820..3ab85c68f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
@@ -7,9 +7,11 @@ use chalk_recursive::Cache;
use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
use base_db::CrateId;
-use hir_def::{lang_item::LangItemTarget, TraitId};
+use hir_def::{
+ lang_item::{LangItem, LangItemTarget},
+ TraitId,
+};
use stdx::panic_context;
-use syntax::SmolStr;
use crate::{
db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
@@ -177,18 +179,18 @@ pub enum FnTrait {
}
impl FnTrait {
- const fn lang_item_name(self) -> &'static str {
+ const fn lang_item(self) -> LangItem {
match self {
- FnTrait::FnOnce => "fn_once",
- FnTrait::FnMut => "fn_mut",
- FnTrait::Fn => "fn",
+ FnTrait::FnOnce => LangItem::FnOnce,
+ FnTrait::FnMut => LangItem::FnMut,
+ FnTrait::Fn => LangItem::Fn,
}
}
pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
- let target = db.lang_item(krate, SmolStr::new_inline(self.lang_item_name()))?;
+ let target = db.lang_item(krate, self.lang_item())?;
match target {
- LangItemTarget::TraitId(t) => Some(t),
+ LangItemTarget::Trait(t) => Some(t),
_ => None,
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 9893566bd..70d2d5efa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -11,39 +11,100 @@ use hir_def::{
GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
WherePredicateTypeTarget,
},
- intern::Interned,
+ lang_item::LangItem,
resolver::{HasResolver, TypeNs},
type_ref::{TraitBoundModifier, TypeRef},
ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId,
TypeOrConstParamId, TypeParamId,
};
use hir_expand::name::Name;
+use intern::Interned;
use itertools::Either;
use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec};
-use syntax::SmolStr;
use crate::{
db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, WhereClause,
};
-pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
- [
- db.lang_item(krate, SmolStr::new_inline("fn")),
- db.lang_item(krate, SmolStr::new_inline("fn_mut")),
- db.lang_item(krate, SmolStr::new_inline("fn_once")),
- ]
- .into_iter()
- .flatten()
- .flat_map(|it| it.as_trait())
+pub(crate) fn fn_traits(
+ db: &dyn DefDatabase,
+ krate: CrateId,
+) -> impl Iterator<Item = TraitId> + '_ {
+ [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce]
+ .into_iter()
+ .filter_map(move |lang| db.lang_item(krate, lang))
+ .flat_map(|it| it.as_trait())
}
-fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
+/// Returns an iterator over the whole super trait hierarchy (including the
+/// trait itself).
+pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
+ // we need to take care a bit here to avoid infinite loops in case of cycles
+ // (i.e. if we have `trait A: B; trait B: A;`)
+
+ let mut result = smallvec![trait_];
+ let mut i = 0;
+ while let Some(&t) = result.get(i) {
+ // yeah this is quadratic, but trait hierarchies should be flat
+ // enough that this doesn't matter
+ direct_super_traits(db, t, |tt| {
+ if !result.contains(&tt) {
+ result.push(tt);
+ }
+ });
+ i += 1;
+ }
+ result
+}
+
+/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
+/// super traits. The original trait ref will be included. So the difference to
+/// `all_super_traits` is that we keep track of type parameters; for example if
+/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
+/// `Self: OtherTrait<i32>`.
+pub(super) fn all_super_trait_refs<T>(
+ db: &dyn HirDatabase,
+ trait_ref: TraitRef,
+ cb: impl FnMut(TraitRef) -> Option<T>,
+) -> Option<T> {
+ let seen = iter::once(trait_ref.trait_id).collect();
+ let mut stack = Vec::new();
+ stack.push(trait_ref);
+ SuperTraits { db, seen, stack }.find_map(cb)
+}
+
+struct SuperTraits<'a> {
+ db: &'a dyn HirDatabase,
+ stack: Vec<TraitRef>,
+ seen: FxHashSet<ChalkTraitId>,
+}
+
+impl<'a> SuperTraits<'a> {
+ fn elaborate(&mut self, trait_ref: &TraitRef) {
+ direct_super_trait_refs(self.db, trait_ref, |trait_ref| {
+ if !self.seen.contains(&trait_ref.trait_id) {
+ self.stack.push(trait_ref);
+ }
+ });
+ }
+}
+
+impl<'a> Iterator for SuperTraits<'a> {
+ type Item = TraitRef;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if let Some(next) = self.stack.pop() {
+ self.elaborate(&next);
+ Some(next)
+ } else {
+ None
+ }
+ }
+}
+
+fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
let resolver = trait_.resolver(db);
- // returning the iterator directly doesn't easily work because of
- // lifetime problems, but since there usually shouldn't be more than a
- // few direct traits this should be fine (we could even use some kind of
- // SmallVec if performance is a concern)
let generic_params = db.generic_params(trait_.into());
let trait_self = generic_params.find_trait_self_param();
generic_params
@@ -73,18 +134,14 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[Trait
Some(TypeNs::TraitId(t)) => Some(t),
_ => None,
})
- .collect()
+ .for_each(cb);
}
-fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<TraitRef> {
- // returning the iterator directly doesn't easily work because of
- // lifetime problems, but since there usually shouldn't be more than a
- // few direct traits this should be fine (we could even use some kind of
- // SmallVec if performance is a concern)
+fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) {
let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
let trait_self = match generic_params.find_trait_self_param() {
Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
- None => return Vec::new(),
+ None => return,
};
db.generic_predicates_for_param(trait_self.parent, trait_self, None)
.iter()
@@ -100,64 +157,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
})
})
.map(|pred| pred.substitute(Interner, &trait_ref.substitution))
- .collect()
-}
-
-/// Returns an iterator over the whole super trait hierarchy (including the
-/// trait itself).
-pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
- // we need to take care a bit here to avoid infinite loops in case of cycles
- // (i.e. if we have `trait A: B; trait B: A;`)
-
- let mut result = smallvec![trait_];
- let mut i = 0;
- while let Some(&t) = result.get(i) {
- // yeah this is quadratic, but trait hierarchies should be flat
- // enough that this doesn't matter
- for tt in direct_super_traits(db, t) {
- if !result.contains(&tt) {
- result.push(tt);
- }
- }
- i += 1;
- }
- result
-}
-
-/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
-/// super traits. The original trait ref will be included. So the difference to
-/// `all_super_traits` is that we keep track of type parameters; for example if
-/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
-/// `Self: OtherTrait<i32>`.
-pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> SuperTraits<'_> {
- SuperTraits { db, seen: iter::once(trait_ref.trait_id).collect(), stack: vec![trait_ref] }
-}
-
-pub(super) struct SuperTraits<'a> {
- db: &'a dyn HirDatabase,
- stack: Vec<TraitRef>,
- seen: FxHashSet<ChalkTraitId>,
-}
-
-impl<'a> SuperTraits<'a> {
- fn elaborate(&mut self, trait_ref: &TraitRef) {
- let mut trait_refs = direct_super_trait_refs(self.db, trait_ref);
- trait_refs.retain(|tr| !self.seen.contains(&tr.trait_id));
- self.stack.extend(trait_refs);
- }
-}
-
-impl<'a> Iterator for SuperTraits<'a> {
- type Item = TraitRef;
-
- fn next(&mut self) -> Option<Self::Item> {
- if let Some(next) = self.stack.pop() {
- self.elaborate(&next);
- Some(next)
- } else {
- None
- }
- }
+ .for_each(cb);
}
pub(super) fn associated_type_by_name_including_super_traits(
@@ -165,7 +165,7 @@ pub(super) fn associated_type_by_name_including_super_traits(
trait_ref: TraitRef,
name: &Name,
) -> Option<(TraitRef, TypeAliasId)> {
- all_super_trait_refs(db, trait_ref).find_map(|t| {
+ all_super_trait_refs(db, trait_ref, |t| {
let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?;
Some((t, assoc_type))
})
@@ -238,15 +238,18 @@ impl Generics {
/// (parent total, self param, type param list, const param list, impl trait)
pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
- let ty_iter = || self.params.iter().filter_map(|x| x.1.type_param());
-
- let self_params =
- ty_iter().filter(|p| p.provenance == TypeParamProvenance::TraitSelf).count();
- let type_params =
- ty_iter().filter(|p| p.provenance == TypeParamProvenance::TypeParamList).count();
- let impl_trait_params =
- ty_iter().filter(|p| p.provenance == TypeParamProvenance::ArgumentImplTrait).count();
- let const_params = self.params.iter().filter_map(|x| x.1.const_param()).count();
+ let mut self_params = 0;
+ let mut type_params = 0;
+ let mut impl_trait_params = 0;
+ let mut const_params = 0;
+ self.params.iter().for_each(|(_, data)| match data {
+ TypeOrConstParamData::TypeParamData(p) => match p.provenance {
+ TypeParamProvenance::TypeParamList => type_params += 1,
+ TypeParamProvenance::TraitSelf => self_params += 1,
+ TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1,
+ },
+ TypeOrConstParamData::ConstParamData(_) => const_params += 1,
+ });
let parent_len = self.parent_generics().map_or(0, Generics::len);
(parent_len, self_params, type_params, const_params, impl_trait_params)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/walk.rs b/src/tools/rust-analyzer/crates/hir-ty/src/walk.rs
deleted file mode 100644
index c47689455..000000000
--- a/src/tools/rust-analyzer/crates/hir-ty/src/walk.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-//! The `TypeWalk` trait (probably to be replaced by Chalk's `Fold` and
-//! `Visit`).
-
-use chalk_ir::interner::HasInterner;
-
-use crate::{
- AliasEq, AliasTy, Binders, CallableSig, FnSubst, GenericArg, GenericArgData, Interner,
- OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind, WhereClause,
-};
-
-/// This allows walking structures that contain types to do something with those
-/// types, similar to Chalk's `Fold` trait.
-pub trait TypeWalk {
- fn walk(&self, f: &mut impl FnMut(&Ty));
-}
-
-impl TypeWalk for Ty {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- match self.kind(Interner) {
- TyKind::Alias(AliasTy::Projection(p_ty)) => {
- for t in p_ty.substitution.iter(Interner) {
- t.walk(f);
- }
- }
- TyKind::Alias(AliasTy::Opaque(o_ty)) => {
- for t in o_ty.substitution.iter(Interner) {
- t.walk(f);
- }
- }
- TyKind::Dyn(dyn_ty) => {
- for p in dyn_ty.bounds.skip_binders().interned().iter() {
- p.walk(f);
- }
- }
- TyKind::Slice(ty)
- | TyKind::Array(ty, _)
- | TyKind::Ref(_, _, ty)
- | TyKind::Raw(_, ty) => {
- ty.walk(f);
- }
- TyKind::Function(fn_pointer) => {
- fn_pointer.substitution.0.walk(f);
- }
- TyKind::Adt(_, substs)
- | TyKind::FnDef(_, substs)
- | TyKind::Tuple(_, substs)
- | TyKind::OpaqueType(_, substs)
- | TyKind::AssociatedType(_, substs)
- | TyKind::Closure(.., substs) => {
- substs.walk(f);
- }
- _ => {}
- }
- f(self);
- }
-}
-
-impl<T: TypeWalk> TypeWalk for Vec<T> {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- for t in self {
- t.walk(f);
- }
- }
-}
-
-impl TypeWalk for OpaqueTy {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- self.substitution.walk(f);
- }
-}
-
-impl TypeWalk for ProjectionTy {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- self.substitution.walk(f);
- }
-}
-
-impl TypeWalk for AliasTy {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- match self {
- AliasTy::Projection(it) => it.walk(f),
- AliasTy::Opaque(it) => it.walk(f),
- }
- }
-}
-
-impl TypeWalk for GenericArg {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- if let GenericArgData::Ty(ty) = &self.interned() {
- ty.walk(f);
- }
- }
-}
-
-impl TypeWalk for Substitution {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- for t in self.iter(Interner) {
- t.walk(f);
- }
- }
-}
-
-impl<T: TypeWalk + HasInterner<Interner = Interner>> TypeWalk for Binders<T> {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- self.skip_binders().walk(f);
- }
-}
-
-impl TypeWalk for TraitRef {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- self.substitution.walk(f);
- }
-}
-
-impl TypeWalk for WhereClause {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- match self {
- WhereClause::Implemented(trait_ref) => trait_ref.walk(f),
- WhereClause::AliasEq(alias_eq) => alias_eq.walk(f),
- _ => {}
- }
- }
-}
-
-impl TypeWalk for CallableSig {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- for t in self.params_and_return.iter() {
- t.walk(f);
- }
- }
-}
-
-impl TypeWalk for AliasEq {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- self.ty.walk(f);
- match &self.alias {
- AliasTy::Projection(projection_ty) => projection_ty.walk(f),
- AliasTy::Opaque(opaque) => opaque.walk(f),
- }
- }
-}
-
-impl TypeWalk for FnSubst<Interner> {
- fn walk(&self, f: &mut impl FnMut(&Ty)) {
- self.0.walk(f)
- }
-}