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.toml10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/builder.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs31
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs87
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs116
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs97
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs85
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/interner.rs67
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs279
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs134
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs208
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs73
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs54
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs248
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs29
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs50
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs81
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tls.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs70
36 files changed, 1544 insertions, 447 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index a1d6835bf..ae837ac6d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -13,18 +13,20 @@ doctest = false
cov-mark = "2.0.0-pre.1"
itertools = "0.10.5"
arrayvec = "0.7.2"
+bitflags = "1.3.2"
smallvec = "1.10.0"
ena = "0.14.0"
tracing = "0.1.35"
rustc-hash = "1.1.0"
scoped-tls = "1.0.0"
-chalk-solve = { version = "0.86.0", default-features = false }
-chalk-ir = "0.86.0"
-chalk-recursive = { version = "0.86.0", default-features = false }
-chalk-derive = "0.86.0"
+chalk-solve = { version = "0.88.0", default-features = false }
+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"
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" }
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 78911d8dc..cbcf8f74c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -82,11 +82,11 @@ pub(crate) fn autoderef_step(
}
// FIXME: replace uses of this with Autoderef above
-pub fn autoderef<'a>(
- db: &'a dyn HirDatabase,
+pub fn autoderef(
+ db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
ty: Canonical<Ty>,
-) -> impl Iterator<Item = Canonical<Ty>> + 'a {
+) -> impl Iterator<Item = Canonical<Ty>> + '_ {
let mut table = InferenceTable::new(db, env);
let ty = table.instantiate_canonical(ty);
let mut autoderef = Autoderef::new(&mut table, ty);
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 9ae752556..d5ef0c22d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
@@ -142,7 +142,7 @@ impl<D> TyBuilder<D> {
match (a.data(Interner), e) {
(chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
| (chalk_ir::GenericArgData::Const(_), ParamKind::Const(_)) => (),
- _ => panic!("Mismatched kinds: {:?}, {:?}, {:?}", a, self.vec, self.param_kinds),
+ _ => panic!("Mismatched kinds: {a:?}, {:?}, {:?}", self.vec, self.param_kinds),
}
}
}
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 43c3451ca..1c2b8de7f 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
@@ -568,6 +568,7 @@ fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> {
"sized" => WellKnownTrait::Sized,
"unpin" => WellKnownTrait::Unpin,
"unsize" => WellKnownTrait::Unsize,
+ "tuple_trait" => WellKnownTrait::Tuple,
_ => return None,
})
}
@@ -585,6 +586,7 @@ fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str {
WellKnownTrait::FnOnce => "fn_once",
WellKnownTrait::Generator => "generator",
WellKnownTrait::Sized => "sized",
+ WellKnownTrait::Tuple => "tuple_trait",
WellKnownTrait::Unpin => "unpin",
WellKnownTrait::Unsize => "unsize",
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index 2c0c6e0b8..8df70330f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -90,14 +90,14 @@ impl Display for ComputedExpr {
ComputedExpr::Literal(l) => match l {
Literal::Int(x, _) => {
if *x >= 10 {
- write!(f, "{} ({:#X})", x, x)
+ write!(f, "{x} ({x:#X})")
} else {
x.fmt(f)
}
}
Literal::Uint(x, _) => {
if *x >= 10 {
- write!(f, "{} ({:#X})", x, x)
+ write!(f, "{x} ({x:#X})")
} else {
x.fmt(f)
}
@@ -131,7 +131,7 @@ fn scalar_max(scalar: &Scalar) -> i128 {
IntTy::I16 => i16::MAX as i128,
IntTy::I32 => i32::MAX as i128,
IntTy::I64 => i64::MAX as i128,
- IntTy::I128 => i128::MAX as i128,
+ IntTy::I128 => i128::MAX,
},
Scalar::Uint(x) => match x {
chalk_ir::UintTy::Usize => usize::MAX as i128,
@@ -139,7 +139,7 @@ fn scalar_max(scalar: &Scalar) -> i128 {
chalk_ir::UintTy::U16 => u16::MAX as i128,
chalk_ir::UintTy::U32 => u32::MAX as i128,
chalk_ir::UintTy::U64 => u64::MAX as i128,
- chalk_ir::UintTy::U128 => i128::MAX as i128, // ignore too big u128 for now
+ chalk_ir::UintTy::U128 => i128::MAX, // ignore too big u128 for now
},
Scalar::Float(_) => 0,
}
@@ -351,15 +351,17 @@ pub fn eval_const(
.infer
.assoc_resolutions_for_expr(expr_id)
.ok_or(ConstEvalError::SemanticError("unresolved assoc item"))?
+ .0
{
hir_def::AssocItemId::FunctionId(_) => {
Err(ConstEvalError::NotSupported("assoc function"))
}
+ // FIXME use actual impl for trait assoc const
hir_def::AssocItemId::ConstId(c) => ctx.db.const_eval(c),
hir_def::AssocItemId::TypeAliasId(_) => {
Err(ConstEvalError::NotSupported("assoc type alias"))
}
- }
+ };
}
};
match pr {
@@ -402,7 +404,7 @@ pub(crate) fn path_to_const(
args_lazy: impl FnOnce() -> Generics,
debruijn: DebruijnIndex,
) -> Option<Const> {
- match resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
+ match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) {
Some(ValueNs::GenericParam(p)) => {
let ty = db.const_param_ty(p);
let args = args_lazy();
@@ -509,10 +511,10 @@ pub(crate) fn const_eval_query_variant(
)
}
-pub(crate) fn eval_to_const<'a>(
+pub(crate) fn eval_to_const(
expr: Idx<Expr>,
mode: ParamLoweringMode,
- ctx: &mut InferenceContext<'a>,
+ ctx: &mut InferenceContext<'_>,
args: impl FnOnce() -> Generics,
debruijn: DebruijnIndex,
) -> Const {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index b76506f6e..3c930c077 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -14,7 +14,7 @@ fn check_number(ra_fixture: &str, answer: i128) {
match r {
ComputedExpr::Literal(Literal::Int(r, _)) => assert_eq!(r, answer),
ComputedExpr::Literal(Literal::Uint(r, _)) => assert_eq!(r, answer as u128),
- x => panic!("Expected number but found {:?}", x),
+ x => panic!("Expected number but found {x:?}"),
}
}
@@ -25,7 +25,6 @@ fn eval_goal(ra_fixture: &str) -> Result<ComputedExpr, ConstEvalError> {
let scope = &def_map[module_id.local_id].scope;
let const_id = scope
.declarations()
- .into_iter()
.find_map(|x| match x {
hir_def::ModuleDefId::ConstId(x) => {
if db.const_data(x).name.as_ref()?.to_string() == "GOAL" {
@@ -126,7 +125,7 @@ fn enums() {
assert_eq!(name, "E::A");
assert_eq!(val, 1);
}
- x => panic!("Expected enum but found {:?}", x),
+ x => panic!("Expected enum but found {x:?}"),
}
}
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 932fce835..54b244620 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -3,20 +3,23 @@
use std::sync::Arc;
-use arrayvec::ArrayVec;
use base_db::{impl_intern_key, salsa, CrateId, Upcast};
use hir_def::{
- db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId,
- FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
+ db::DefDatabase,
+ expr::ExprId,
+ layout::{Layout, LayoutError, TargetDataLayout},
+ AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GenericDefId,
+ ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
};
use la_arena::ArenaMap;
+use smallvec::SmallVec;
use crate::{
chalk_db,
consteval::{ComputedExpr, ConstEvalError},
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
Binders, CallableDefId, FnDefId, GenericArg, ImplTraitId, InferenceResult, Interner, PolyFnSig,
- QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
+ QuantifiedWhereClause, ReturnTypeImplTraits, Substitution, TraitRef, Ty, TyDefId, ValueTyDefId,
};
use hir_expand::name::Name;
@@ -57,6 +60,13 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::lower::field_types_query)]
fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
+ #[salsa::invoke(crate::layout::layout_of_adt_query)]
+ #[salsa::cycle(crate::layout::layout_of_adt_recover)]
+ 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>;
+
#[salsa::invoke(crate::lower::callable_item_sig)]
fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
@@ -92,10 +102,15 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn inherent_impls_in_block(&self, block: BlockId) -> Option<Arc<InherentImpls>>;
/// Collects all crates in the dependency graph that have impls for the
- /// given fingerprint. This is only used for primitive types; for
- /// user-defined types we just look at the crate where the type is defined.
- #[salsa::invoke(crate::method_resolution::inherent_impl_crates_query)]
- fn inherent_impl_crates(&self, krate: CrateId, fp: TyFingerprint) -> ArrayVec<CrateId, 2>;
+ /// given fingerprint. This is only used for primitive types and types
+ /// annotated with `rustc_has_incoherent_inherent_impls`; for other types
+ /// we just look at the crate where the type is defined.
+ #[salsa::invoke(crate::method_resolution::incoherent_inherent_impl_crates)]
+ fn incoherent_inherent_impl_crates(
+ &self,
+ krate: CrateId,
+ fp: TyFingerprint,
+ ) -> SmallVec<[CrateId; 2]>;
#[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
index d51ad72bd..8b0f051b4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
@@ -12,16 +12,16 @@ pub(crate) mod usefulness;
use chalk_ir::Mutability;
use hir_def::{
- adt::VariantData, body::Body, expr::PatId, AdtId, EnumVariantId, HasModule, LocalFieldId,
- VariantId,
+ adt::VariantData, body::Body, expr::PatId, AdtId, EnumVariantId, LocalFieldId, VariantId,
};
-use hir_expand::name::{name, Name};
+use hir_expand::name::Name;
use stdx::{always, never};
use crate::{
db::HirDatabase,
display::{HirDisplay, HirDisplayError, HirFormatter},
infer::BindingMode,
+ lang_items::is_box,
InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
};
@@ -386,7 +386,7 @@ impl HirDisplay for Pat {
}
subpattern.hir_fmt(f)
}
- PatKind::LiteralBool { value } => write!(f, "{}", value),
+ PatKind::LiteralBool { value } => write!(f, "{value}"),
PatKind::Or { pats } => f.write_joined(pats.iter(), " | "),
}
}
@@ -405,13 +405,6 @@ where
}
}
-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);
- Some(adt) == box_adt
-}
-
pub(crate) trait PatternFoldable: Sized {
fn fold_with<F: PatternFolder>(&self, folder: &mut F) -> Self {
self.super_fold_with(folder)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
index 47d60fc41..d130827a7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
@@ -372,7 +372,7 @@ impl Constructor {
hir_def::AdtId::UnionId(id) => id.into(),
}
}
- _ => panic!("bad constructor {:?} for adt {:?}", self, adt),
+ _ => panic!("bad constructor {self:?} for adt {adt:?}"),
}
}
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 a22a4b170..66e813eed 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -16,7 +16,7 @@ use hir_def::{
path::{Path, PathKind},
type_ref::{ConstScalar, TraitBoundModifier, TypeBound, TypeRef},
visibility::Visibility,
- HasModule, ItemContainerId, Lookup, ModuleId, TraitId,
+ HasModule, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
};
use hir_expand::{hygiene::Hygiene, name::Name};
use itertools::Itertools;
@@ -35,9 +35,27 @@ use crate::{
TraitRefExt, Ty, TyExt, TyKind, WhereClause,
};
+pub trait HirWrite: fmt::Write {
+ fn start_location_link(&mut self, location: ModuleDefId);
+ fn end_location_link(&mut self);
+}
+
+// String will ignore link metadata
+impl HirWrite for String {
+ fn start_location_link(&mut self, _: ModuleDefId) {}
+
+ fn end_location_link(&mut self) {}
+}
+
+// `core::Formatter` will ignore metadata
+impl HirWrite for fmt::Formatter<'_> {
+ fn start_location_link(&mut self, _: ModuleDefId) {}
+ fn end_location_link(&mut self) {}
+}
+
pub struct HirFormatter<'a> {
pub db: &'a dyn HirDatabase,
- fmt: &'a mut dyn fmt::Write,
+ fmt: &'a mut dyn HirWrite,
buf: String,
curr_size: usize,
pub(crate) max_size: Option<usize>,
@@ -45,6 +63,16 @@ pub struct HirFormatter<'a> {
display_target: DisplayTarget,
}
+impl HirFormatter<'_> {
+ fn start_location_link(&mut self, location: ModuleDefId) {
+ self.fmt.start_location_link(location);
+ }
+
+ fn end_location_link(&mut self) {
+ self.fmt.end_location_link();
+ }
+}
+
pub trait HirDisplay {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>;
@@ -148,13 +176,13 @@ impl<'a> HirFormatter<'a> {
let mut first = true;
for e in iter {
if !first {
- write!(self, "{}", sep)?;
+ write!(self, "{sep}")?;
}
first = false;
// Abbreviate multiple omitted types with a single ellipsis.
if self.should_truncate() {
- return write!(self, "{}", TYPE_HINT_TRUNCATION);
+ return write!(self, "{TYPE_HINT_TRUNCATION}");
}
e.hir_fmt(self)?;
@@ -245,12 +273,9 @@ pub struct HirDisplayWrapper<'a, T> {
display_target: DisplayTarget,
}
-impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
-where
- T: HirDisplay,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.t.hir_fmt(&mut HirFormatter {
+impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
+ pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result<(), HirDisplayError> {
+ self.t.hir_fmt(&mut HirFormatter {
db: self.db,
fmt: f,
buf: String::with_capacity(20),
@@ -258,7 +283,16 @@ where
max_size: self.max_size,
omit_verbose_types: self.omit_verbose_types,
display_target: self.display_target,
- }) {
+ })
+ }
+}
+
+impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
+where
+ T: HirDisplay,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.write_to(f) {
Ok(()) => Ok(()),
Err(HirDisplayError::FmtError) => Err(fmt::Error),
Err(HirDisplayError::DisplaySourceCodeError(_)) => {
@@ -286,7 +320,7 @@ impl<T: HirDisplay + Internable> HirDisplay for Interned<T> {
impl HirDisplay for ProjectionTy {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
if f.should_truncate() {
- return write!(f, "{}", TYPE_HINT_TRUNCATION);
+ return write!(f, "{TYPE_HINT_TRUNCATION}");
}
let trait_ref = self.trait_ref(f.db);
@@ -308,7 +342,7 @@ impl HirDisplay for ProjectionTy {
impl HirDisplay for OpaqueTy {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
if f.should_truncate() {
- return write!(f, "{}", TYPE_HINT_TRUNCATION);
+ return write!(f, "{TYPE_HINT_TRUNCATION}");
}
self.substitution.at(Interner, 0).hir_fmt(f)
@@ -351,7 +385,7 @@ impl HirDisplay for BoundVar {
impl HirDisplay for Ty {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
if f.should_truncate() {
- return write!(f, "{}", TYPE_HINT_TRUNCATION);
+ return write!(f, "{TYPE_HINT_TRUNCATION}");
}
match self.kind(Interner) {
@@ -530,6 +564,7 @@ impl HirDisplay for Ty {
}
}
TyKind::Adt(AdtId(def_id), parameters) => {
+ f.start_location_link((*def_id).into());
match f.display_target {
DisplayTarget::Diagnostics | DisplayTarget::Test => {
let name = match *def_id {
@@ -537,7 +572,7 @@ impl HirDisplay for Ty {
hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
};
- write!(f, "{}", name)?;
+ write!(f, "{name}")?;
}
DisplayTarget::SourceCode { module_id } => {
if let Some(path) = find_path::find_path(
@@ -546,7 +581,7 @@ impl HirDisplay for Ty {
module_id,
false,
) {
- write!(f, "{}", path)?;
+ write!(f, "{path}")?;
} else {
return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::PathNotFound,
@@ -554,6 +589,7 @@ impl HirDisplay for Ty {
}
}
}
+ f.end_location_link();
if parameters.len(Interner) > 0 {
let parameters_to_write = if f.display_target.is_source_code()
@@ -701,7 +737,7 @@ impl HirDisplay for Ty {
if sig.params().is_empty() {
write!(f, "||")?;
} else if f.should_truncate() {
- write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
+ write!(f, "|{TYPE_HINT_TRUNCATION}|")?;
} else {
write!(f, "|")?;
f.write_joined(sig.params(), ", ")?;
@@ -892,7 +928,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix(
default_sized: SizedByDefault,
f: &mut HirFormatter<'_>,
) -> Result<(), HirDisplayError> {
- write!(f, "{}", prefix)?;
+ write!(f, "{prefix}")?;
if !predicates.is_empty()
|| predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
{
@@ -1020,7 +1056,7 @@ fn fmt_trait_ref(
use_as: bool,
) -> Result<(), HirDisplayError> {
if f.should_truncate() {
- return write!(f, "{}", TYPE_HINT_TRUNCATION);
+ return write!(f, "{TYPE_HINT_TRUNCATION}");
}
tr.self_type_parameter(Interner).hir_fmt(f)?;
@@ -1047,7 +1083,7 @@ impl HirDisplay for TraitRef {
impl HirDisplay for WhereClause {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
if f.should_truncate() {
- return write!(f, "{}", TYPE_HINT_TRUNCATION);
+ return write!(f, "{TYPE_HINT_TRUNCATION}");
}
match self {
@@ -1098,7 +1134,6 @@ impl HirDisplay for LifetimeData {
write!(f, "{}", param_data.name)
}
LifetimeData::Static => write!(f, "'static"),
- LifetimeData::Empty(_) => Ok(()),
LifetimeData::Erased => Ok(()),
LifetimeData::Phantom(_, _) => Ok(()),
}
@@ -1162,7 +1197,7 @@ impl HirDisplay for TypeRef {
hir_def::type_ref::Mutability::Shared => "*const ",
hir_def::type_ref::Mutability::Mut => "*mut ",
};
- write!(f, "{}", mutability)?;
+ write!(f, "{mutability}")?;
inner.hir_fmt(f)?;
}
TypeRef::Reference(inner, lifetime, mutability) => {
@@ -1174,13 +1209,13 @@ impl HirDisplay for TypeRef {
if let Some(lifetime) = lifetime {
write!(f, "{} ", lifetime.name)?;
}
- write!(f, "{}", mutability)?;
+ write!(f, "{mutability}")?;
inner.hir_fmt(f)?;
}
TypeRef::Array(inner, len) => {
write!(f, "[")?;
inner.hir_fmt(f)?;
- write!(f, "; {}]", len)?;
+ write!(f, "; {len}]")?;
}
TypeRef::Slice(inner) => {
write!(f, "[")?;
@@ -1197,7 +1232,7 @@ impl HirDisplay for TypeRef {
for index in 0..function_parameters.len() {
let (param_name, param_type) = &function_parameters[index];
if let Some(name) = param_name {
- write!(f, "{}: ", name)?;
+ write!(f, "{name}: ")?;
}
param_type.hir_fmt(f)?;
@@ -1373,7 +1408,7 @@ impl HirDisplay for hir_def::path::GenericArg {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
match self {
hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
- hir_def::path::GenericArg::Const(c) => write!(f, "{}", c),
+ hir_def::path::GenericArg::Const(c) => write!(f, "{c}"),
hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
}
}
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 0b3c23f57..6b59f1c20 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -19,10 +19,11 @@ use std::sync::Arc;
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
use hir_def::{
body::Body,
- builtin_type::BuiltinType,
+ builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
data::{ConstData, StaticData},
- expr::{BindingAnnotation, ExprId, PatId},
+ expr::{BindingAnnotation, ExprId, ExprOrPatId, PatId},
lang_item::LangItemTarget,
+ layout::Integer,
path::{path, Path},
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
type_ref::TypeRef,
@@ -33,7 +34,7 @@ use hir_expand::name::{name, Name};
use itertools::Either;
use la_arena::ArenaMap;
use rustc_hash::FxHashMap;
-use stdx::{always, impl_from};
+use stdx::always;
use crate::{
db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
@@ -70,8 +71,26 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
DefWithBodyId::VariantId(v) => {
ctx.return_ty = TyBuilder::builtin(match db.enum_data(v.parent).variant_body_type() {
- Either::Left(builtin) => BuiltinType::Int(builtin),
- Either::Right(builtin) => BuiltinType::Uint(builtin),
+ hir_def::layout::IntegerType::Pointer(signed) => match signed {
+ true => BuiltinType::Int(BuiltinInt::Isize),
+ false => BuiltinType::Uint(BuiltinUint::Usize),
+ },
+ hir_def::layout::IntegerType::Fixed(size, signed) => match signed {
+ true => BuiltinType::Int(match size {
+ Integer::I8 => BuiltinInt::I8,
+ Integer::I16 => BuiltinInt::I16,
+ Integer::I32 => BuiltinInt::I32,
+ Integer::I64 => BuiltinInt::I64,
+ Integer::I128 => BuiltinInt::I128,
+ }),
+ false => BuiltinType::Uint(match size {
+ Integer::I8 => BuiltinUint::U8,
+ Integer::I16 => BuiltinUint::U16,
+ Integer::I32 => BuiltinUint::U32,
+ Integer::I64 => BuiltinUint::U64,
+ Integer::I128 => BuiltinUint::U128,
+ }),
+ },
});
}
}
@@ -101,13 +120,6 @@ pub(crate) fn normalize(db: &dyn HirDatabase, owner: DefWithBodyId, ty: Ty) -> T
table.resolve_completely(ty_with_vars)
}
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-enum ExprOrPatId {
- ExprId(ExprId),
- PatId(PatId),
-}
-impl_from!(ExprId, PatId for ExprOrPatId);
-
/// Binding modes inferred for patterns.
/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -189,6 +201,8 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum InferenceDiagnostic {
NoSuchField { expr: ExprId },
+ PrivateField { expr: ExprId, field: FieldId },
+ PrivateAssocItem { id: ExprOrPatId, item: AssocItemId },
BreakOutsideOfLoop { expr: ExprId, is_break: bool },
MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
}
@@ -330,7 +344,7 @@ pub struct InferenceResult {
/// For each struct literal or pattern, records the variant it resolves to.
variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
/// For each associated item record what it resolves to
- assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
+ assoc_resolutions: FxHashMap<ExprOrPatId, (AssocItemId, Substitution)>,
pub diagnostics: Vec<InferenceDiagnostic>,
pub type_of_expr: ArenaMap<ExprId, Ty>,
/// For each pattern record the type it resolves to.
@@ -360,11 +374,11 @@ impl InferenceResult {
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
self.variant_resolutions.get(&id.into()).copied()
}
- pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItemId> {
- self.assoc_resolutions.get(&id.into()).copied()
+ pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<(AssocItemId, Substitution)> {
+ self.assoc_resolutions.get(&id.into()).cloned()
}
- pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItemId> {
- self.assoc_resolutions.get(&id.into()).copied()
+ pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<(AssocItemId, Substitution)> {
+ self.assoc_resolutions.get(&id.into()).cloned()
}
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
self.type_mismatches.get(&expr.into())
@@ -484,7 +498,7 @@ impl<'a> InferenceContext<'a> {
result: InferenceResult::default(),
table: unify::InferenceTable::new(db, trait_env.clone()),
trait_env,
- return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
+ return_ty: TyKind::Error.intern(Interner), // set in collect_* calls
resume_yield_tys: None,
db,
owner,
@@ -498,6 +512,8 @@ impl<'a> InferenceContext<'a> {
fn resolve_all(self) -> InferenceResult {
let InferenceContext { mut table, mut result, .. } = self;
+ table.fallback_if_possible();
+
// FIXME resolve obligations as well (use Guidance if necessary)
table.resolve_obligations_as_possible();
@@ -516,6 +532,9 @@ impl<'a> InferenceContext<'a> {
for (_, subst) in result.method_resolutions.values_mut() {
*subst = table.resolve_completely(subst.clone());
}
+ for (_, subst) in result.assoc_resolutions.values_mut() {
+ *subst = table.resolve_completely(subst.clone());
+ }
for adjustment in result.expr_adjustments.values_mut().flatten() {
adjustment.target = table.resolve_completely(adjustment.target.clone());
}
@@ -537,8 +556,20 @@ impl<'a> InferenceContext<'a> {
let data = self.db.function_data(func);
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
.with_impl_trait_mode(ImplTraitLoweringMode::Param);
- let param_tys =
+ let mut param_tys =
data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
+ // Check if function contains a va_list, if it does then we append it to the parameter types
+ // that are collected from the function data
+ if data.is_varargs() {
+ let va_list_ty = match self.resolve_va_list() {
+ Some(va_list) => TyBuilder::adt(self.db, va_list)
+ .fill_with_defaults(self.db, || self.table.new_type_var())
+ .build(),
+ None => self.err_ty(),
+ };
+
+ param_tys.push(va_list_ty)
+ }
for (ty, pat) in param_tys.into_iter().zip(self.body.params.iter()) {
let ty = self.insert_type_vars(ty);
let ty = self.normalize_associated_types_in(ty);
@@ -551,14 +582,17 @@ impl<'a> InferenceContext<'a> {
} else {
&*data.ret_type
};
- let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Opaque);
- self.return_ty = return_ty;
- if let Some(rpits) = self.db.return_type_impl_traits(func) {
+ let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+ let return_ty = ctx.lower_ty(return_ty);
+ let return_ty = self.insert_type_vars(return_ty);
+
+ let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
// RPIT opaque types use substitution of their parent function.
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
- self.return_ty = fold_tys(
- self.return_ty.clone(),
+ fold_tys(
+ return_ty,
|ty, _| {
let opaque_ty_id = match ty.kind(Interner) {
TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
@@ -579,14 +613,18 @@ impl<'a> InferenceContext<'a> {
let (var_predicate, binders) = predicate
.substitute(Interner, &var_subst)
.into_value_and_skipped_binders();
- always!(binders.len(Interner) == 0); // quantified where clauses not yet handled
+ always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
self.push_obligation(var_predicate.cast(Interner));
}
var
},
DebruijnIndex::INNERMOST,
- );
- }
+ )
+ } else {
+ return_ty
+ };
+
+ self.return_ty = self.normalize_associated_types_in(return_ty);
}
fn infer_body(&mut self) {
@@ -609,8 +647,8 @@ impl<'a> InferenceContext<'a> {
self.result.variant_resolutions.insert(id, variant);
}
- fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId) {
- self.result.assoc_resolutions.insert(id, item);
+ fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId, subs: Substitution) {
+ self.result.assoc_resolutions.insert(id, (item, subs));
}
fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
@@ -621,23 +659,14 @@ impl<'a> InferenceContext<'a> {
self.result.diagnostics.push(diagnostic);
}
- fn make_ty_with_mode(
- &mut self,
- type_ref: &TypeRef,
- impl_trait_mode: ImplTraitLoweringMode,
- ) -> Ty {
+ fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
// FIXME use right resolver for block
- let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
- .with_impl_trait_mode(impl_trait_mode);
+ let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
let ty = ctx.lower_ty(type_ref);
let ty = self.insert_type_vars(ty);
self.normalize_associated_types_in(ty)
}
- fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
- self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
- }
-
fn err_ty(&self) -> Ty {
self.result.standard_types.unknown.clone()
}
@@ -656,7 +685,7 @@ impl<'a> InferenceContext<'a> {
}
}
- /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
+ /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it.
fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
match ty.kind(Interner) {
TyKind::Error => self.table.new_type_var(),
@@ -983,6 +1012,11 @@ impl<'a> InferenceContext<'a> {
let trait_ = self.resolve_ops_index()?;
self.db.trait_data(trait_).associated_type_by_name(&name![Output])
}
+
+ fn resolve_va_list(&self) -> Option<AdtId> {
+ let struct_ = self.resolve_lang_item(name![va_list])?.as_struct()?;
+ Some(struct_.into())
+ }
}
/// When inferring an expression, we propagate downward whatever type hint we
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 b1f4de826..8f9cdac37 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
@@ -1,13 +1,12 @@
//! Type inference for expressions.
use std::{
- collections::hash_map::Entry,
iter::{repeat, repeat_with},
mem,
};
use chalk_ir::{
- cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
+ cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyKind, TyVariableKind,
};
use hir_def::{
expr::{
@@ -35,8 +34,8 @@ use crate::{
primitive::{self, UintTy},
static_lifetime, to_chalk_trait_id,
utils::{generics, Generics},
- AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar,
- Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
+ Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnPointer, FnSig, FnSubst,
+ Interner, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt,
};
use super::{
@@ -152,11 +151,20 @@ impl<'a> InferenceContext<'a> {
.1
}
Expr::TryBlock { body } => {
- self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
- let _inner = this.infer_expr(*body, expected);
+ // The type that is returned from the try block
+ let try_ty = self.table.new_type_var();
+ if let Some(ty) = expected.only_has_type(&mut self.table) {
+ self.unify(&try_ty, &ty);
+ }
+
+ // 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());
+
+ self.with_breakable_ctx(BreakableKind::Block, ok_ty.clone(), None, |this| {
+ this.infer_expr(*body, &Expectation::has_type(ok_ty));
});
- // FIXME should be std::result::Result<{inner}, _>
- self.err_ty()
+
+ try_ty
}
Expr::Async { body } => {
let ret_ty = self.table.new_type_var();
@@ -326,6 +334,7 @@ impl<'a> InferenceContext<'a> {
let (param_tys, ret_ty) = match res {
Some(res) => {
let adjustments = auto_deref_adjust_steps(&derefs);
+ // FIXME: Handle call adjustments for Fn/FnMut
self.write_expr_adj(*callee, adjustments);
res
}
@@ -465,6 +474,12 @@ impl<'a> InferenceContext<'a> {
TyKind::Error.intern(Interner)
}
}
+ Expr::Yeet { expr } => {
+ if let &Some(expr) = expr {
+ self.infer_expr_inner(expr, &Expectation::None);
+ }
+ TyKind::Never.intern(Interner)
+ }
Expr::RecordLit { path, fields, spread, .. } => {
let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
if let Some(variant) = def_id {
@@ -506,6 +521,7 @@ impl<'a> InferenceContext<'a> {
let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none());
let mut autoderef = Autoderef::new(&mut self.table, receiver_ty);
+ let mut private_field = None;
let ty = autoderef.by_ref().find_map(|(derefed_ty, _)| {
let (field_id, parameters) = match derefed_ty.kind(Interner) {
TyKind::Tuple(_, substs) => {
@@ -532,13 +548,8 @@ impl<'a> InferenceContext<'a> {
let is_visible = self.db.field_visibilities(field_id.parent)[field_id.local_id]
.is_visible_from(self.db.upcast(), self.resolver.module());
if !is_visible {
- // Write down the first field resolution even if it is not visible
- // This aids IDE features for private fields like goto def and in
- // case of autoderef finding an applicable field, this will be
- // overwritten in a following cycle
- if let Entry::Vacant(entry) = self.result.field_resolutions.entry(tgt_expr)
- {
- entry.insert(field_id);
+ if private_field.is_none() {
+ private_field = Some(field_id);
}
return None;
}
@@ -557,7 +568,17 @@ impl<'a> InferenceContext<'a> {
let ty = self.normalize_associated_types_in(ty);
ty
}
- _ => self.err_ty(),
+ _ => {
+ // Write down the first private field resolution if we found no field
+ // This aids IDE features for private fields like goto def
+ if let Some(field) = private_field {
+ self.result.field_resolutions.insert(tgt_expr, field);
+ self.result
+ .diagnostics
+ .push(InferenceDiagnostic::PrivateField { expr: tgt_expr, field });
+ }
+ self.err_ty()
+ }
};
ty
}
@@ -940,7 +961,7 @@ impl<'a> InferenceContext<'a> {
Expr::RecordLit { path, fields, .. } => {
let subs = fields.iter().map(|f| (f.name.clone(), f.expr));
- self.infer_record_pat_like(path.as_deref(), &rhs_ty, (), lhs.into(), subs)
+ self.infer_record_pat_like(path.as_deref(), &rhs_ty, (), lhs, subs)
}
Expr::Underscore => rhs_ty.clone(),
_ => {
@@ -1018,14 +1039,38 @@ impl<'a> InferenceContext<'a> {
self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone()));
let ret_ty = match method_ty.callable_sig(self.db) {
- Some(sig) => sig.ret().clone(),
+ Some(sig) => {
+ let p_left = &sig.params()[0];
+ if matches!(op, BinaryOp::CmpOp(..) | BinaryOp::Assignment { .. }) {
+ if let &TyKind::Ref(mtbl, _, _) = p_left.kind(Interner) {
+ self.write_expr_adj(
+ lhs,
+ vec![Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(mtbl)),
+ target: p_left.clone(),
+ }],
+ );
+ }
+ }
+ let p_right = &sig.params()[1];
+ if matches!(op, BinaryOp::CmpOp(..)) {
+ if let &TyKind::Ref(mtbl, _, _) = p_right.kind(Interner) {
+ self.write_expr_adj(
+ rhs,
+ vec![Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(mtbl)),
+ target: p_right.clone(),
+ }],
+ );
+ }
+ }
+ sig.ret().clone()
+ }
None => self.err_ty(),
};
let ret_ty = self.normalize_associated_types_in(ret_ty);
- // FIXME: record autoref adjustments
-
// 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);
@@ -1122,20 +1167,26 @@ impl<'a> InferenceContext<'a> {
let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
let resolved = method_resolution::lookup_method(
- &canonicalized_receiver.value,
self.db,
+ &canonicalized_receiver.value,
self.trait_env.clone(),
&traits_in_scope,
VisibleFromModule::Filter(self.resolver.module()),
method_name,
);
let (receiver_ty, method_ty, substs) = match resolved {
- Some((adjust, func)) => {
+ Some((adjust, func, visible)) => {
let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty);
let generics = generics(self.db.upcast(), func.into());
let substs = self.substs_for_method_call(generics, generic_args);
self.write_expr_adj(receiver, adjustments);
self.write_method_resolution(tgt_expr, func, substs.clone());
+ if !visible {
+ self.push_diagnostic(InferenceDiagnostic::PrivateAssocItem {
+ id: tgt_expr.into(),
+ item: func.into(),
+ })
+ }
(ty, self.db.value_ty(func.into()), substs)
}
None => (
@@ -1309,7 +1360,7 @@ impl<'a> InferenceContext<'a> {
ty,
c,
ParamLoweringMode::Placeholder,
- || generics(this.db.upcast(), (&this.resolver).generic_def().unwrap()),
+ || generics(this.db.upcast(), this.resolver.generic_def().unwrap()),
DebruijnIndex::INNERMOST,
)
},
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index 53259d66d..f154dac8e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -153,7 +153,7 @@ impl<'a> InferenceContext<'a> {
) -> Ty {
let mut expected = self.resolve_ty_shallow(expected);
- if is_non_ref_pat(&self.body, pat) {
+ if is_non_ref_pat(self.body, pat) {
let mut pat_adjustments = Vec::new();
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
pat_adjustments.push(expected.clone());
@@ -220,7 +220,7 @@ impl<'a> InferenceContext<'a> {
),
Pat::Record { path: p, args: fields, ellipsis: _ } => {
let subs = fields.iter().map(|f| (f.name.clone(), f.pat));
- self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat.into(), subs)
+ self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat, subs)
}
Pat::Path(path) => {
// FIXME use correct resolver for the surrounding expression
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 ebe9d6fb5..8bd17c0f3 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
@@ -7,13 +7,15 @@ use hir_def::{
AdtId, AssocItemId, EnumVariantId, ItemContainerId, Lookup,
};
use hir_expand::name::Name;
+use stdx::never;
use crate::{
builder::ParamKind,
consteval,
method_resolution::{self, VisibleFromModule},
utils::generics,
- Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
+ InferenceDiagnostic, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
+ ValueTyDefId,
};
use super::{ExprOrPatId, InferenceContext, TraitRef};
@@ -212,7 +214,7 @@ impl<'a> InferenceContext<'a> {
AssocItemId::TypeAliasId(_) => unreachable!(),
};
- self.write_assoc_resolution(id, item);
+ self.write_assoc_resolution(id, item, trait_ref.substitution.clone());
Some((def, Some(trait_ref.substitution)))
}
@@ -233,7 +235,8 @@ impl<'a> InferenceContext<'a> {
let canonical_ty = self.canonicalize(ty.clone());
let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
- method_resolution::iterate_method_candidates(
+ let mut not_visible = None;
+ let res = method_resolution::iterate_method_candidates(
&canonical_ty.value,
self.db,
self.table.trait_env.clone(),
@@ -241,7 +244,7 @@ impl<'a> InferenceContext<'a> {
VisibleFromModule::Filter(self.resolver.module()),
Some(name),
method_resolution::LookupMode::Path,
- move |_ty, item| {
+ |_ty, item, visible| {
let (def, container) = match item {
AssocItemId::FunctionId(f) => {
(ValueNs::FunctionId(f), f.lookup(self.db.upcast()).container)
@@ -259,7 +262,7 @@ impl<'a> InferenceContext<'a> {
let impl_self_ty =
self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs);
self.unify(&impl_self_ty, &ty);
- Some(impl_substs)
+ impl_substs
}
ItemContainerId::TraitId(trait_) => {
// we're picking this method
@@ -268,15 +271,32 @@ impl<'a> InferenceContext<'a> {
.fill_with_inference_vars(&mut self.table)
.build();
self.push_obligation(trait_ref.clone().cast(Interner));
- Some(trait_ref.substitution)
+ trait_ref.substitution
+ }
+ ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
+ never!("assoc item contained in module/extern block");
+ return None;
}
- ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
};
- self.write_assoc_resolution(id, item);
- Some((def, substs))
+ if visible {
+ Some((def, item, Some(substs), true))
+ } else {
+ if not_visible.is_none() {
+ not_visible = Some((def, item, Some(substs), false));
+ }
+ None
+ }
},
- )
+ );
+ let res = res.or(not_visible);
+ if let Some((_, item, Some(ref substs), visible)) = res {
+ self.write_assoc_resolution(id, item, substs.clone());
+ if !visible {
+ self.push_diagnostic(InferenceDiagnostic::PrivateAssocItem { id, item })
+ }
+ }
+ res.map(|(def, _, substs, _)| (def, substs))
}
fn resolve_enum_variant_on_ty(
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 12f45f00f..e7ddd1591 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
@@ -1,6 +1,6 @@
//! Unification and canonicalization logic.
-use std::{fmt, mem, sync::Arc};
+use std::{fmt, iter, mem, sync::Arc};
use chalk_ir::{
cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy,
@@ -128,9 +128,13 @@ pub(crate) fn unify(
))
}
-#[derive(Copy, Clone, Debug)]
-pub(crate) struct TypeVariableData {
- diverging: bool,
+bitflags::bitflags! {
+ #[derive(Default)]
+ pub(crate) struct TypeVariableFlags: u8 {
+ const DIVERGING = 1 << 0;
+ const INTEGER = 1 << 1;
+ const FLOAT = 1 << 2;
+ }
}
type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
@@ -140,14 +144,14 @@ pub(crate) struct InferenceTable<'a> {
pub(crate) db: &'a dyn HirDatabase,
pub(crate) trait_env: Arc<TraitEnvironment>,
var_unification_table: ChalkInferenceTable,
- type_variable_table: Vec<TypeVariableData>,
+ type_variable_table: Vec<TypeVariableFlags>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
}
pub(crate) struct InferenceTableSnapshot {
var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
- type_variable_table_snapshot: Vec<TypeVariableData>,
+ type_variable_table_snapshot: Vec<TypeVariableFlags>,
}
impl<'a> InferenceTable<'a> {
@@ -169,19 +173,19 @@ impl<'a> InferenceTable<'a> {
/// result.
pub(super) fn propagate_diverging_flag(&mut self) {
for i in 0..self.type_variable_table.len() {
- if !self.type_variable_table[i].diverging {
+ if !self.type_variable_table[i].contains(TypeVariableFlags::DIVERGING) {
continue;
}
let v = InferenceVar::from(i as u32);
let root = self.var_unification_table.inference_var_root(v);
if let Some(data) = self.type_variable_table.get_mut(root.index() as usize) {
- data.diverging = true;
+ *data |= TypeVariableFlags::DIVERGING;
}
}
}
pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) {
- self.type_variable_table[iv.index() as usize].diverging = diverging;
+ self.type_variable_table[iv.index() as usize].set(TypeVariableFlags::DIVERGING, diverging);
}
fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
@@ -189,7 +193,7 @@ impl<'a> InferenceTable<'a> {
_ if self
.type_variable_table
.get(iv.index() as usize)
- .map_or(false, |data| data.diverging) =>
+ .map_or(false, |data| data.contains(TypeVariableFlags::DIVERGING)) =>
{
TyKind::Never
}
@@ -247,10 +251,8 @@ impl<'a> InferenceTable<'a> {
}
fn extend_type_variable_table(&mut self, to_index: usize) {
- self.type_variable_table.extend(
- (0..1 + to_index - self.type_variable_table.len())
- .map(|_| TypeVariableData { diverging: false }),
- );
+ let count = to_index - self.type_variable_table.len() + 1;
+ self.type_variable_table.extend(iter::repeat(TypeVariableFlags::default()).take(count));
}
fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
@@ -258,7 +260,15 @@ impl<'a> InferenceTable<'a> {
// Chalk might have created some type variables for its own purposes that we don't know about...
self.extend_type_variable_table(var.index() as usize);
assert_eq!(var.index() as usize, self.type_variable_table.len() - 1);
- self.type_variable_table[var.index() as usize].diverging = diverging;
+ let flags = self.type_variable_table.get_mut(var.index() as usize).unwrap();
+ if diverging {
+ *flags |= TypeVariableFlags::DIVERGING;
+ }
+ if matches!(kind, TyVariableKind::Integer) {
+ *flags |= TypeVariableFlags::INTEGER;
+ } else if matches!(kind, TyVariableKind::Float) {
+ *flags |= TypeVariableFlags::FLOAT;
+ }
var.to_ty_with_kind(Interner, kind)
}
@@ -340,6 +350,51 @@ impl<'a> InferenceTable<'a> {
self.resolve_with_fallback(t, &|_, _, d, _| d)
}
+ /// Apply a fallback to unresolved scalar types. Integer type variables and float type
+ /// variables are replaced with i32 and f64, respectively.
+ ///
+ /// This method is only intended to be called just before returning inference results (i.e. in
+ /// `InferenceContext::resolve_all()`).
+ ///
+ /// FIXME: This method currently doesn't apply fallback to unconstrained general type variables
+ /// whereas rustc replaces them with `()` or `!`.
+ pub(super) fn fallback_if_possible(&mut self) {
+ let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner);
+ let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner);
+
+ let scalar_vars: Vec<_> = self
+ .type_variable_table
+ .iter()
+ .enumerate()
+ .filter_map(|(index, flags)| {
+ let kind = if flags.contains(TypeVariableFlags::INTEGER) {
+ TyVariableKind::Integer
+ } else if flags.contains(TypeVariableFlags::FLOAT) {
+ TyVariableKind::Float
+ } else {
+ return None;
+ };
+
+ // FIXME: This is not really the nicest way to get `InferenceVar`s. Can we get them
+ // without directly constructing them from `index`?
+ let var = InferenceVar::from(index as u32).to_ty(Interner, kind);
+ Some(var)
+ })
+ .collect();
+
+ for var in scalar_vars {
+ let maybe_resolved = self.resolve_ty_shallow(&var);
+ if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) {
+ let fallback = match kind {
+ TyVariableKind::Integer => &int_fallback,
+ TyVariableKind::Float => &float_fallback,
+ TyVariableKind::General => unreachable!(),
+ };
+ self.unify(&var, fallback);
+ }
+ }
+ }
+
/// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
pub(crate) fn unify<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool {
let result = match self.try_unify(ty1, ty2) {
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 ca76e08fd..441503a30 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs
@@ -143,7 +143,7 @@ impl chalk_ir::interner::Interner for Interner {
fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
let goal_data = goal.data(Interner);
- Some(write!(fmt, "{:?}", goal_data))
+ Some(write!(fmt, "{goal_data:?}"))
}
fn debug_goals(
@@ -228,7 +228,7 @@ impl chalk_ir::interner::Interner for Interner {
Interned::new(InternedWrapper(chalk_ir::TyData { kind, flags }))
}
- fn ty_data<'a>(self, ty: &'a Self::InternedType) -> &'a chalk_ir::TyData<Self> {
+ fn ty_data(self, ty: &Self::InternedType) -> &chalk_ir::TyData<Self> {
&ty.0
}
@@ -236,10 +236,7 @@ impl chalk_ir::interner::Interner for Interner {
Interned::new(InternedWrapper(lifetime))
}
- fn lifetime_data<'a>(
- self,
- lifetime: &'a Self::InternedLifetime,
- ) -> &'a chalk_ir::LifetimeData<Self> {
+ fn lifetime_data(self, lifetime: &Self::InternedLifetime) -> &chalk_ir::LifetimeData<Self> {
&lifetime.0
}
@@ -247,7 +244,7 @@ impl chalk_ir::interner::Interner for Interner {
Interned::new(InternedWrapper(constant))
}
- fn const_data<'a>(self, constant: &'a Self::InternedConst) -> &'a chalk_ir::ConstData<Self> {
+ fn const_data(self, constant: &Self::InternedConst) -> &chalk_ir::ConstData<Self> {
&constant.0
}
@@ -267,10 +264,10 @@ impl chalk_ir::interner::Interner for Interner {
parameter
}
- fn generic_arg_data<'a>(
+ fn generic_arg_data(
self,
- parameter: &'a Self::InternedGenericArg,
- ) -> &'a chalk_ir::GenericArgData<Self> {
+ parameter: &Self::InternedGenericArg,
+ ) -> &chalk_ir::GenericArgData<Self> {
parameter
}
@@ -285,11 +282,11 @@ impl chalk_ir::interner::Interner for Interner {
data.into_iter().collect()
}
- fn goal_data<'a>(self, goal: &'a Self::InternedGoal) -> &'a GoalData<Self> {
+ fn goal_data(self, goal: &Self::InternedGoal) -> &GoalData<Self> {
goal
}
- fn goals_data<'a>(self, goals: &'a Self::InternedGoals) -> &'a [Goal<Interner>] {
+ fn goals_data(self, goals: &Self::InternedGoals) -> &[Goal<Interner>] {
goals
}
@@ -300,10 +297,7 @@ impl chalk_ir::interner::Interner for Interner {
Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
}
- fn substitution_data<'a>(
- self,
- substitution: &'a Self::InternedSubstitution,
- ) -> &'a [GenericArg] {
+ fn substitution_data(self, substitution: &Self::InternedSubstitution) -> &[GenericArg] {
&substitution.as_ref().0
}
@@ -314,10 +308,10 @@ impl chalk_ir::interner::Interner for Interner {
data
}
- fn program_clause_data<'a>(
+ fn program_clause_data(
self,
- clause: &'a Self::InternedProgramClause,
- ) -> &'a chalk_ir::ProgramClauseData<Self> {
+ clause: &Self::InternedProgramClause,
+ ) -> &chalk_ir::ProgramClauseData<Self> {
clause
}
@@ -328,10 +322,10 @@ impl chalk_ir::interner::Interner for Interner {
Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
}
- fn program_clauses_data<'a>(
+ fn program_clauses_data(
self,
- clauses: &'a Self::InternedProgramClauses,
- ) -> &'a [chalk_ir::ProgramClause<Self>] {
+ clauses: &Self::InternedProgramClauses,
+ ) -> &[chalk_ir::ProgramClause<Self>] {
clauses
}
@@ -342,10 +336,10 @@ impl chalk_ir::interner::Interner for Interner {
Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
}
- fn quantified_where_clauses_data<'a>(
+ fn quantified_where_clauses_data(
self,
- clauses: &'a Self::InternedQuantifiedWhereClauses,
- ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] {
+ clauses: &Self::InternedQuantifiedWhereClauses,
+ ) -> &[chalk_ir::QuantifiedWhereClause<Self>] {
clauses
}
@@ -356,10 +350,10 @@ impl chalk_ir::interner::Interner for Interner {
Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
}
- fn variable_kinds_data<'a>(
+ fn variable_kinds_data(
self,
- parameter_kinds: &'a Self::InternedVariableKinds,
- ) -> &'a [chalk_ir::VariableKind<Self>] {
+ parameter_kinds: &Self::InternedVariableKinds,
+ ) -> &[chalk_ir::VariableKind<Self>] {
&parameter_kinds.as_ref().0
}
@@ -370,10 +364,10 @@ impl chalk_ir::interner::Interner for Interner {
Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
}
- fn canonical_var_kinds_data<'a>(
+ fn canonical_var_kinds_data(
self,
- canonical_var_kinds: &'a Self::InternedCanonicalVarKinds,
- ) -> &'a [chalk_ir::CanonicalVarKind<Self>] {
+ canonical_var_kinds: &Self::InternedCanonicalVarKinds,
+ ) -> &[chalk_ir::CanonicalVarKind<Self>] {
canonical_var_kinds
}
@@ -384,10 +378,10 @@ impl chalk_ir::interner::Interner for Interner {
data.into_iter().collect()
}
- fn constraints_data<'a>(
+ fn constraints_data(
self,
- constraints: &'a Self::InternedConstraints,
- ) -> &'a [chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>] {
+ constraints: &Self::InternedConstraints,
+ ) -> &[chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>] {
constraints
}
fn debug_closure_id(
@@ -410,10 +404,7 @@ impl chalk_ir::interner::Interner for Interner {
Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
}
- fn variances_data<'a>(
- self,
- variances: &'a Self::InternedVariances,
- ) -> &'a [chalk_ir::Variance] {
+ fn variances_data(self, variances: &Self::InternedVariances) -> &[chalk_ir::Variance] {
variances
}
}
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
new file mode 100644
index 000000000..afc54e729
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs
@@ -0,0 +1,20 @@
+//! Functions to detect special lang items
+
+use hir_def::{AdtId, HasModule};
+use hir_expand::name;
+
+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);
+ 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);
+ 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
new file mode 100644
index 000000000..7a1cca314
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -0,0 +1,279 @@
+//! Compute the binary representation of a type
+
+use std::sync::Arc;
+
+use base_db::CrateId;
+use chalk_ir::{AdtId, TyKind};
+use hir_def::{
+ layout::{
+ Abi, FieldsShape, Integer, Layout, LayoutCalculator, LayoutError, Primitive, ReprOptions,
+ RustcEnumVariantIdx, Scalar, Size, StructKind, TargetDataLayout, Variants, WrappingRange,
+ },
+ LocalFieldId,
+};
+use stdx::never;
+
+use crate::{db::HirDatabase, Interner, Substitution, Ty};
+
+use self::adt::struct_variant_idx;
+pub use self::{
+ adt::{layout_of_adt_query, layout_of_adt_recover},
+ target::target_data_layout_query,
+};
+
+macro_rules! user_error {
+ ($x: expr) => {
+ return Err(LayoutError::UserError(format!($x)))
+ };
+}
+
+mod adt;
+mod target;
+
+struct LayoutCx<'a> {
+ db: &'a dyn HirDatabase,
+ krate: CrateId,
+}
+
+impl LayoutCalculator for LayoutCx<'_> {
+ type TargetDataLayoutRef = Arc<TargetDataLayout>;
+
+ fn delay_bug(&self, txt: &str) {
+ never!("{}", txt);
+ }
+
+ fn current_data_layout(&self) -> Arc<TargetDataLayout> {
+ self.db.target_data_layout(self.krate)
+ }
+}
+
+fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar {
+ Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) }
+}
+
+fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout {
+ Layout::scalar(dl, scalar_unit(dl, value))
+}
+
+pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Layout, LayoutError> {
+ let cx = LayoutCx { db, krate };
+ let dl = &*cx.current_data_layout();
+ Ok(match ty.kind(Interner) {
+ TyKind::Adt(AdtId(def), subst) => db.layout_of_adt(*def, subst.clone())?,
+ TyKind::Scalar(s) => match s {
+ chalk_ir::Scalar::Bool => Layout::scalar(
+ dl,
+ Scalar::Initialized {
+ value: Primitive::Int(Integer::I8, false),
+ valid_range: WrappingRange { start: 0, end: 1 },
+ },
+ ),
+ chalk_ir::Scalar::Char => Layout::scalar(
+ dl,
+ Scalar::Initialized {
+ value: Primitive::Int(Integer::I32, false),
+ valid_range: WrappingRange { start: 0, end: 0x10FFFF },
+ },
+ ),
+ chalk_ir::Scalar::Int(i) => scalar(
+ dl,
+ Primitive::Int(
+ match i {
+ chalk_ir::IntTy::Isize => dl.ptr_sized_integer(),
+ chalk_ir::IntTy::I8 => Integer::I8,
+ chalk_ir::IntTy::I16 => Integer::I16,
+ chalk_ir::IntTy::I32 => Integer::I32,
+ chalk_ir::IntTy::I64 => Integer::I64,
+ chalk_ir::IntTy::I128 => Integer::I128,
+ },
+ true,
+ ),
+ ),
+ chalk_ir::Scalar::Uint(i) => scalar(
+ dl,
+ Primitive::Int(
+ match i {
+ chalk_ir::UintTy::Usize => dl.ptr_sized_integer(),
+ chalk_ir::UintTy::U8 => Integer::I8,
+ chalk_ir::UintTy::U16 => Integer::I16,
+ chalk_ir::UintTy::U32 => Integer::I32,
+ chalk_ir::UintTy::U64 => Integer::I64,
+ chalk_ir::UintTy::U128 => Integer::I128,
+ },
+ false,
+ ),
+ ),
+ chalk_ir::Scalar::Float(f) => scalar(
+ dl,
+ match f {
+ chalk_ir::FloatTy::F32 => Primitive::F32,
+ chalk_ir::FloatTy::F64 => Primitive::F64,
+ },
+ ),
+ },
+ TyKind::Tuple(len, tys) => {
+ let kind = if *len == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
+
+ let fields = tys
+ .iter(Interner)
+ .map(|k| layout_of_ty(db, k.assert_ty_ref(Interner), krate))
+ .collect::<Result<Vec<_>, _>>()?;
+ let fields = fields.iter().collect::<Vec<_>>();
+ let fields = fields.iter().collect::<Vec<_>>();
+ cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)?
+ }
+ TyKind::Array(element, count) => {
+ let count = match count.data(Interner).value {
+ chalk_ir::ConstValue::Concrete(c) => match c.interned {
+ hir_def::type_ref::ConstScalar::Int(x) => x as u64,
+ hir_def::type_ref::ConstScalar::UInt(x) => x as u64,
+ hir_def::type_ref::ConstScalar::Unknown => {
+ user_error!("unknown const generic parameter")
+ }
+ _ => user_error!("mismatched type of const generic parameter"),
+ },
+ _ => return Err(LayoutError::HasPlaceholder),
+ };
+ let element = layout_of_ty(db, element, krate)?;
+ let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;
+
+ let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) {
+ Abi::Uninhabited
+ } else {
+ Abi::Aggregate { sized: true }
+ };
+
+ let largest_niche = if count != 0 { element.largest_niche } else { None };
+
+ Layout {
+ variants: Variants::Single { index: struct_variant_idx() },
+ fields: FieldsShape::Array { stride: element.size, count },
+ abi,
+ largest_niche,
+ align: element.align,
+ size,
+ }
+ }
+ TyKind::Slice(element) => {
+ let element = layout_of_ty(db, element, krate)?;
+ Layout {
+ variants: Variants::Single { index: struct_variant_idx() },
+ fields: FieldsShape::Array { stride: element.size, count: 0 },
+ abi: Abi::Aggregate { sized: false },
+ largest_niche: None,
+ align: element.align,
+ size: Size::ZERO,
+ }
+ }
+ // Potentially-wide pointers.
+ TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {
+ let mut data_ptr = scalar_unit(dl, Primitive::Pointer);
+ if matches!(ty.kind(Interner), TyKind::Ref(..)) {
+ data_ptr.valid_range_mut().start = 1;
+ }
+
+ // 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)));
+ // }
+
+ let unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
+ let metadata = match unsized_part.kind(Interner) {
+ TyKind::Slice(_) | TyKind::Str => {
+ scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false))
+ }
+ TyKind::Dyn(..) => {
+ let mut vtable = scalar_unit(dl, Primitive::Pointer);
+ vtable.valid_range_mut().start = 1;
+ vtable
+ }
+ _ => {
+ // pointee is sized
+ return Ok(Layout::scalar(dl, data_ptr));
+ }
+ };
+
+ // Effectively a (ptr, meta) tuple.
+ cx.scalar_pair(data_ptr, metadata)
+ }
+ TyKind::FnDef(_, _) => layout_of_unit(&cx, dl)?,
+ TyKind::Str => Layout {
+ variants: Variants::Single { index: struct_variant_idx() },
+ fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
+ abi: Abi::Aggregate { sized: false },
+ largest_niche: None,
+ align: dl.i8_align,
+ size: Size::ZERO,
+ },
+ TyKind::Never => Layout {
+ variants: Variants::Single { index: struct_variant_idx() },
+ fields: FieldsShape::Primitive,
+ abi: Abi::Uninhabited,
+ largest_niche: None,
+ align: dl.i8_align,
+ size: Size::ZERO,
+ },
+ TyKind::Dyn(_) | TyKind::Foreign(_) => {
+ let mut unit = layout_of_unit(&cx, dl)?;
+ match unit.abi {
+ Abi::Aggregate { ref mut sized } => *sized = false,
+ _ => user_error!("bug"),
+ }
+ unit
+ }
+ TyKind::Function(_) => {
+ let mut ptr = scalar_unit(dl, Primitive::Pointer);
+ ptr.valid_range_mut().start = 1;
+ Layout::scalar(dl, ptr)
+ }
+ TyKind::Closure(_, _)
+ | TyKind::OpaqueType(_, _)
+ | TyKind::Generator(_, _)
+ | TyKind::GeneratorWitness(_, _) => return Err(LayoutError::NotImplemented),
+ TyKind::AssociatedType(_, _)
+ | TyKind::Error
+ | TyKind::Alias(_)
+ | TyKind::Placeholder(_)
+ | TyKind::BoundVar(_)
+ | TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),
+ })
+}
+
+fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> {
+ cx.univariant::<RustcEnumVariantIdx, &&Layout>(
+ dl,
+ &[],
+ &ReprOptions::default(),
+ StructKind::AlwaysSized,
+ )
+ .ok_or(LayoutError::Unknown)
+}
+
+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,
+ }
+ }
+ _ => pointee,
+ },
+ _ => pointee,
+ }
+}
+
+fn field_ty(
+ db: &dyn HirDatabase,
+ def: hir_def::VariantId,
+ fd: LocalFieldId,
+ subst: &Substitution,
+) -> Ty {
+ db.field_types(def)[fd].clone().substitute(Interner, subst)
+}
+
+#[cfg(test)]
+mod tests;
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
new file mode 100644
index 000000000..23166a5a5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
@@ -0,0 +1,134 @@
+//! Compute the binary representation of structs, unions and enums
+
+use std::ops::Bound;
+
+use hir_def::{
+ adt::VariantData,
+ layout::{Integer, IntegerExt, Layout, LayoutCalculator, LayoutError, RustcEnumVariantIdx},
+ AdtId, EnumVariantId, HasModule, LocalEnumVariantId, VariantId,
+};
+use la_arena::RawIdx;
+use smallvec::SmallVec;
+
+use crate::{db::HirDatabase, lang_items::is_unsafe_cell, layout::field_ty, Substitution};
+
+use super::{layout_of_ty, LayoutCx};
+
+pub(crate) fn struct_variant_idx() -> RustcEnumVariantIdx {
+ RustcEnumVariantIdx(LocalEnumVariantId::from_raw(RawIdx::from(0)))
+}
+
+pub fn layout_of_adt_query(
+ db: &dyn HirDatabase,
+ def: AdtId,
+ subst: Substitution,
+) -> Result<Layout, LayoutError> {
+ let cx = LayoutCx { db, krate: def.module(db.upcast()).krate() };
+ let dl = cx.current_data_layout();
+ let handle_variant = |def: VariantId, var: &VariantData| {
+ var.fields()
+ .iter()
+ .map(|(fd, _)| layout_of_ty(db, &field_ty(db, def, fd, &subst), cx.krate))
+ .collect::<Result<Vec<_>, _>>()
+ };
+ let (variants, is_enum, is_union, repr) = match def {
+ AdtId::StructId(s) => {
+ let data = db.struct_data(s);
+ let mut r = SmallVec::<[_; 1]>::new();
+ r.push(handle_variant(s.into(), &data.variant_data)?);
+ (r, false, false, data.repr.unwrap_or_default())
+ }
+ AdtId::UnionId(id) => {
+ let data = db.union_data(id);
+ let mut r = SmallVec::new();
+ r.push(handle_variant(id.into(), &data.variant_data)?);
+ (r, false, true, data.repr.unwrap_or_default())
+ }
+ AdtId::EnumId(e) => {
+ let data = db.enum_data(e);
+ let r = data
+ .variants
+ .iter()
+ .map(|(idx, v)| {
+ handle_variant(
+ EnumVariantId { parent: e, local_id: idx }.into(),
+ &v.variant_data,
+ )
+ })
+ .collect::<Result<SmallVec<_>, _>>()?;
+ (r, true, false, data.repr.unwrap_or_default())
+ }
+ };
+ let variants =
+ variants.iter().map(|x| x.iter().collect::<Vec<_>>()).collect::<SmallVec<[_; 1]>>();
+ let variants = variants.iter().map(|x| x.iter().collect()).collect();
+ if is_union {
+ cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown)
+ } else {
+ cx.layout_of_struct_or_enum(
+ &repr,
+ &variants,
+ is_enum,
+ is_unsafe_cell(def, db),
+ layout_scalar_valid_range(db, def),
+ |min, max| Integer::repr_discr(&dl, &repr, min, max).unwrap_or((Integer::I8, false)),
+ variants.iter_enumerated().filter_map(|(id, _)| {
+ let AdtId::EnumId(e) = def else { return None };
+ let d = match db
+ .const_eval_variant(EnumVariantId { parent: e, local_id: id.0 })
+ .ok()?
+ {
+ crate::consteval::ComputedExpr::Literal(l) => match l {
+ hir_def::expr::Literal::Int(i, _) => i,
+ hir_def::expr::Literal::Uint(i, _) => i as i128,
+ _ => return None,
+ },
+ _ => return None,
+ };
+ Some((id, d))
+ }),
+ // FIXME: The current code for niche-filling relies on variant indices
+ // instead of actual discriminants, so enums with
+ // explicit discriminants (RFC #2363) would misbehave and we should disable
+ // niche optimization for them.
+ // The code that do it in rustc:
+ // repr.inhibit_enum_layout_opt() || def
+ // .variants()
+ // .iter_enumerated()
+ // .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()))
+ repr.inhibit_enum_layout_opt(),
+ !is_enum
+ && variants
+ .iter()
+ .next()
+ .and_then(|x| x.last().map(|x| x.is_unsized()))
+ .unwrap_or(true),
+ )
+ .ok_or(LayoutError::SizeOverflow)
+ }
+}
+
+fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound<u128>, Bound<u128>) {
+ let attrs = db.attrs(def.into());
+ let get = |name| {
+ let attr = attrs.by_key(name).tt_values();
+ for tree in attr {
+ if let Some(x) = tree.token_trees.first() {
+ if let Ok(x) = x.to_string().parse() {
+ return Bound::Included(x);
+ }
+ }
+ }
+ Bound::Unbounded
+ };
+ (get("rustc_layout_scalar_valid_range_start"), get("rustc_layout_scalar_valid_range_end"))
+}
+
+pub fn layout_of_adt_recover(
+ _: &dyn HirDatabase,
+ _: &[String],
+ _: &AdtId,
+ _: &Substitution,
+) -> Result<Layout, LayoutError> {
+ user_error!("infinite sized recursive type");
+}
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
new file mode 100644
index 000000000..37b831652
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
@@ -0,0 +1,36 @@
+//! Target dependent parameters needed for layouts
+
+use std::sync::Arc;
+
+use base_db::CrateId;
+use hir_def::layout::{Endian, Size, TargetDataLayout};
+
+use crate::db::HirDatabase;
+
+pub fn target_data_layout_query(db: &dyn HirDatabase, krate: CrateId) -> 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() }
+ }),
+ )
+}
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
new file mode 100644
index 000000000..53838cf41
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
@@ -0,0 +1,208 @@
+use base_db::fixture::WithFixture;
+use chalk_ir::{AdtId, TyKind};
+use hir_def::{
+ db::DefDatabase,
+ layout::{Layout, LayoutError},
+};
+
+use crate::{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();
+
+ let ra_fixture = format!(
+ "{minicore}//- /main.rs crate:test target_data_layout:{target_data_layout}\n{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::AdtId(x) => {
+ let name = match x {
+ hir_def::AdtId::StructId(x) => db.struct_data(x).name.to_smol_str(),
+ hir_def::AdtId::UnionId(x) => db.union_data(x).name.to_smol_str(),
+ hir_def::AdtId::EnumId(x) => db.enum_data(x).name.to_smol_str(),
+ };
+ (name == "Goal").then_some(x)
+ }
+ _ => None,
+ })
+ .unwrap();
+ let goal_ty = TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner);
+ 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();
+ 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));
+}
+
+macro_rules! size_and_align {
+ (minicore: $($x:tt),*;$($t:tt)*) => {
+ {
+ #[allow(dead_code)]
+ $($t)*
+ check_size_and_align(
+ stringify!($($t)*),
+ &format!("//- minicore: {}\n", stringify!($($x),*)),
+ ::std::mem::size_of::<Goal>() as u64,
+ ::std::mem::align_of::<Goal>() as u64,
+ );
+ }
+ };
+ ($($t:tt)*) => {
+ {
+ #[allow(dead_code)]
+ $($t)*
+ check_size_and_align(
+ stringify!($($t)*),
+ "",
+ ::std::mem::size_of::<Goal>() as u64,
+ ::std::mem::align_of::<Goal>() as u64,
+ );
+ }
+ };
+}
+
+#[test]
+fn hello_world() {
+ size_and_align! {
+ struct Goal(i32);
+ }
+}
+
+#[test]
+fn field_order_optimization() {
+ size_and_align! {
+ struct Goal(u8, i32, u8);
+ }
+ size_and_align! {
+ #[repr(C)]
+ struct Goal(u8, i32, u8);
+ }
+}
+
+#[test]
+fn recursive() {
+ size_and_align! {
+ struct Goal {
+ left: &'static Goal,
+ right: &'static Goal,
+ }
+ }
+ size_and_align! {
+ struct BoxLike<T: ?Sized>(*mut T);
+ struct Goal(BoxLike<Goal>);
+ }
+ check_fail(
+ r#"struct Goal(Goal);"#,
+ LayoutError::UserError("infinite sized recursive type".to_string()),
+ );
+ check_fail(
+ r#"
+ struct Foo<T>(Foo<T>);
+ struct Goal(Foo<i32>);
+ "#,
+ LayoutError::UserError("infinite sized recursive type".to_string()),
+ );
+}
+
+#[test]
+fn generic() {
+ size_and_align! {
+ struct Pair<A, B>(A, B);
+ struct Goal(Pair<Pair<i32, u8>, i64>);
+ }
+ size_and_align! {
+ struct X<const N: usize> {
+ field1: [i32; N],
+ field2: [u8; N],
+ }
+ struct Goal(X<1000>);
+ }
+}
+
+#[test]
+fn enums() {
+ size_and_align! {
+ enum Goal {
+ Quit,
+ Move { x: i32, y: i32 },
+ ChangeColor(i32, i32, i32),
+ }
+ }
+}
+
+#[test]
+fn primitives() {
+ size_and_align! {
+ struct Goal(i32, i128, isize, usize, f32, f64, bool, char);
+ }
+}
+
+#[test]
+fn tuple() {
+ size_and_align! {
+ struct Goal((), (i32, u64, bool));
+ }
+}
+
+#[test]
+fn non_zero() {
+ size_and_align! {
+ minicore: non_zero, option;
+ use core::num::NonZeroU8;
+ struct Goal(Option<NonZeroU8>);
+ }
+}
+
+#[test]
+fn niche_optimization() {
+ size_and_align! {
+ minicore: option;
+ struct Goal(Option<&'static i32>);
+ }
+ size_and_align! {
+ minicore: option;
+ struct Goal(Option<Option<bool>>);
+ }
+}
+
+#[test]
+fn enums_with_discriminants() {
+ size_and_align! {
+ enum Goal {
+ A = 1000,
+ B = 2000,
+ C = 3000,
+ }
+ }
+ size_and_align! {
+ enum Goal {
+ A = 254,
+ B,
+ C, // implicitly becomes 256, so we need two bytes
+ }
+ }
+}
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 39514fc44..cbe6873c7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -27,6 +27,8 @@ pub mod display;
pub mod method_resolution;
pub mod primitive;
pub mod traits;
+pub mod layout;
+pub mod lang_items;
#[cfg(test)]
mod tests;
@@ -38,7 +40,7 @@ use std::sync::Arc;
use chalk_ir::{
fold::{Shift, TypeFoldable},
interner::HasInterner,
- NoSolution, UniverseIndex,
+ NoSolution,
};
use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
use hir_expand::name;
@@ -46,7 +48,9 @@ use itertools::Either;
use traits::FnTrait;
use utils::Generics;
-use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
+use crate::{
+ consteval::unknown_const, db::HirDatabase, infer::unify::InferenceTable, utils::generics,
+};
pub use autoderef::autoderef;
pub use builder::{ParamKind, TyBuilder};
@@ -511,7 +515,7 @@ where
let mut error_replacer = ErrorReplacer { vars: 0 };
let value = match t.clone().try_fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
Ok(t) => t,
- Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
+ Err(_) => panic!("Encountered unbound or inference vars in {t:?}"),
};
let kinds = (0..error_replacer.vars).map(|_| {
chalk_ir::CanonicalVarKind::new(
@@ -531,54 +535,31 @@ pub fn callable_sig_from_fnonce(
let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
+ let mut table = InferenceTable::new(db, env.clone());
let b = TyBuilder::trait_ref(db, fn_once_trait);
if b.remaining() != 2 {
return None;
}
- let fn_once = b.push(self_ty.clone()).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
- let kinds = fn_once
- .substitution
- .iter(Interner)
- .skip(1)
- .map(|x| {
- let vk = match x.data(Interner) {
- chalk_ir::GenericArgData::Ty(_) => {
- chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
- }
- chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
- chalk_ir::GenericArgData::Const(c) => {
- chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
- }
- };
- chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
- })
- .collect::<Vec<_>>();
-
- // FIXME: chalk refuses to solve `<Self as FnOnce<^0.0>>::Output == ^0.1`, so we first solve
- // `<Self as FnOnce<^0.0>>` and then replace `^0.0` with the concrete argument tuple.
- let trait_env = env.env.clone();
- let obligation = InEnvironment { goal: fn_once.cast(Interner), environment: trait_env };
- let canonical =
- Canonical { binders: CanonicalVarKinds::from_iter(Interner, kinds), value: obligation };
- let subst = match db.trait_solve(krate, canonical) {
- Some(Solution::Unique(vars)) => vars.value.subst,
- _ => return None,
- };
- let args = subst.at(Interner, 0).ty(Interner)?;
- let params = match args.kind(Interner) {
- chalk_ir::TyKind::Tuple(_, subst) => {
- subst.iter(Interner).filter_map(|arg| arg.ty(Interner).cloned()).collect::<Vec<_>>()
- }
- _ => return None,
- };
- let fn_once =
- TyBuilder::trait_ref(db, fn_once_trait).push(self_ty.clone()).push(args.clone()).build();
- let projection =
- TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution.clone()))
- .build();
+ // Register two obligations:
+ // - Self: FnOnce<?args_ty>
+ // - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
+ let args_ty = table.new_type_var();
+ let trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build();
+ let projection = TyBuilder::assoc_type_projection(
+ db,
+ output_assoc_type,
+ Some(trait_ref.substitution.clone()),
+ )
+ .build();
+ table.register_obligation(trait_ref.cast(Interner));
+ let ret_ty = table.normalize_projection_ty(projection);
+
+ let ret_ty = table.resolve_completely(ret_ty);
+ let args_ty = table.resolve_completely(args_ty);
- let ret_ty = db.normalize_projection(projection, env);
+ let params =
+ args_ty.as_tuple()?.iter(Interner).map(|it| it.assert_ty_ref(Interner)).cloned().collect();
- Some(CallableSig::from_params_and_return(params, ret_ty.clone(), false, Safety::Safe))
+ Some(CallableSig::from_params_and_return(params, ret_ty, false, Safety::Safe))
}
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 baf9842d5..592410008 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -603,9 +603,8 @@ impl<'a> TyLoweringContext<'a> {
}
fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
- let (def, res) = match (self.resolver.generic_def(), res) {
- (Some(def), Some(res)) => (def, res),
- _ => return TyKind::Error.intern(Interner),
+ let Some((def, res)) = self.resolver.generic_def().zip(res) else {
+ return TyKind::Error.intern(Interner);
};
let ty = named_associated_type_shorthand_candidates(
self.db,
@@ -617,6 +616,21 @@ impl<'a> TyLoweringContext<'a> {
return None;
}
+ let parent_subst = t.substitution.clone();
+ let parent_subst = match self.type_param_mode {
+ ParamLoweringMode::Placeholder => {
+ // if we're lowering to placeholders, we have to put them in now.
+ let generics = generics(self.db.upcast(), def);
+ let s = generics.placeholder_subst(self.db);
+ s.apply(parent_subst, Interner)
+ }
+ ParamLoweringMode::Variable => {
+ // We need to shift in the bound vars, since
+ // `named_associated_type_shorthand_candidates` does not do that.
+ parent_subst.shifted_in_from(Interner, self.in_binders)
+ }
+ };
+
// FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
// generic params. It's inefficient to splice the `Substitution`s, so we may want
// that method to optionally take parent `Substitution` as we already know them at
@@ -632,22 +646,9 @@ impl<'a> TyLoweringContext<'a> {
let substs = Substitution::from_iter(
Interner,
- substs.iter(Interner).take(len_self).chain(t.substitution.iter(Interner)),
+ substs.iter(Interner).take(len_self).chain(parent_subst.iter(Interner)),
);
- let substs = match self.type_param_mode {
- ParamLoweringMode::Placeholder => {
- // if we're lowering to placeholders, we have to put
- // them in now
- let generics = generics(self.db.upcast(), def);
- let s = generics.placeholder_subst(self.db);
- s.apply(substs, Interner)
- }
- ParamLoweringMode::Variable => substs,
- };
- // We need to shift in the bound vars, since
- // associated_type_shorthand_candidates does not do that
- let substs = substs.shifted_in_from(Interner, self.in_binders);
Some(
TyKind::Alias(AliasTy::Projection(ProjectionTy {
associated_ty_id: to_assoc_type_id(associated_ty),
@@ -779,7 +780,7 @@ impl<'a> TyLoweringContext<'a> {
|_, c, ty| {
const_or_path_to_chalk(
self.db,
- &self.resolver,
+ self.resolver,
ty,
c,
self.type_param_mode,
@@ -1190,9 +1191,9 @@ pub fn associated_type_shorthand_candidates<R>(
db: &dyn HirDatabase,
def: GenericDefId,
res: TypeNs,
- cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
+ mut cb: impl FnMut(&Name, TypeAliasId) -> Option<R>,
) -> Option<R> {
- named_associated_type_shorthand_candidates(db, def, res, None, cb)
+ named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id))
}
fn named_associated_type_shorthand_candidates<R>(
@@ -1202,6 +1203,9 @@ fn named_associated_type_shorthand_candidates<R>(
def: GenericDefId,
res: TypeNs,
assoc_name: Option<Name>,
+ // Do NOT let `cb` touch `TraitRef` outside of `TyLoweringContext`. Its substitution contains
+ // free `BoundVar`s that need to be shifted and only `TyLoweringContext` knows how to do that
+ // properly (see `TyLoweringContext::select_associated_type()`).
mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
) -> Option<R> {
let mut search = |t| {
@@ -1792,8 +1796,7 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast());
let _cx = stdx::panic_context::enter(format!(
- "impl_self_ty_query({:?} -> {:?} -> {:?})",
- impl_id, impl_loc, impl_data
+ "impl_self_ty_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})"
));
let generics = generics(db.upcast(), impl_id.into());
let ctx =
@@ -1830,8 +1833,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast());
let _cx = stdx::panic_context::enter(format!(
- "impl_trait_query({:?} -> {:?} -> {:?})",
- impl_id, impl_loc, impl_data
+ "impl_trait_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})"
));
let ctx =
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
@@ -1850,7 +1852,7 @@ pub(crate) fn return_type_impl_traits(
let ctx_ret = TyLoweringContext::new(db, &resolver)
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable);
- let _ret = (&ctx_ret).lower_ty(&data.ret_type);
+ 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() };
@@ -1979,7 +1981,7 @@ fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Intern
if bound.index_if_innermost().map_or(true, is_allowed) {
bound.shifted_in_from(binders).to_const(Interner, ty)
} else {
- unknown_const(ty.clone())
+ unknown_const(ty)
}
},
)
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 8bcfa2728..2328dceb8 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
@@ -2,18 +2,17 @@
//! For details about how this works in rustc, see the method lookup page in the
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
//! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs.
-use std::{iter, ops::ControlFlow, sync::Arc};
+use std::{ops::ControlFlow, sync::Arc};
-use arrayvec::ArrayVec;
use base_db::{CrateId, Edition};
use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
use hir_def::{
data::ImplData, item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId,
- FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId,
- TraitId,
+ FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
};
use hir_expand::name::Name;
use rustc_hash::{FxHashMap, FxHashSet};
+use smallvec::{smallvec, SmallVec};
use stdx::never;
use crate::{
@@ -336,21 +335,18 @@ impl InherentImpls {
}
}
-pub(crate) fn inherent_impl_crates_query(
+pub(crate) fn incoherent_inherent_impl_crates(
db: &dyn HirDatabase,
krate: CrateId,
fp: TyFingerprint,
-) -> ArrayVec<CrateId, 2> {
+) -> SmallVec<[CrateId; 2]> {
let _p = profile::span("inherent_impl_crates_query");
- let mut res = ArrayVec::new();
+ let mut res = SmallVec::new();
let crate_graph = db.crate_graph();
+ // should pass crate for finger print and do reverse deps
+
for krate in crate_graph.transitive_deps(krate) {
- if res.is_full() {
- // we don't currently look for or store more than two crates here,
- // so don't needlessly look at more crates than necessary.
- break;
- }
let impls = db.inherent_impls_in_crate(krate);
if impls.map.get(&fp).map_or(false, |v| !v.is_empty()) {
res.push(krate);
@@ -392,19 +388,40 @@ pub fn def_crates(
db: &dyn HirDatabase,
ty: &Ty,
cur_crate: CrateId,
-) -> Option<ArrayVec<CrateId, 2>> {
- let mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect());
-
- let fp = TyFingerprint::for_inherent_impl(ty);
-
+) -> Option<SmallVec<[CrateId; 2]>> {
match ty.kind(Interner) {
- TyKind::Adt(AdtId(def_id), _) => mod_to_crate_ids(def_id.module(db.upcast())),
- TyKind::Foreign(id) => {
- mod_to_crate_ids(from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()))
+ &TyKind::Adt(AdtId(def_id), _) => {
+ let rustc_has_incoherent_inherent_impls = match def_id {
+ hir_def::AdtId::StructId(id) => {
+ db.struct_data(id).rustc_has_incoherent_inherent_impls
+ }
+ hir_def::AdtId::UnionId(id) => {
+ db.union_data(id).rustc_has_incoherent_inherent_impls
+ }
+ hir_def::AdtId::EnumId(id) => db.enum_data(id).rustc_has_incoherent_inherent_impls,
+ };
+ Some(if rustc_has_incoherent_inherent_impls {
+ db.incoherent_inherent_impl_crates(cur_crate, TyFingerprint::Adt(def_id))
+ } else {
+ smallvec![def_id.module(db.upcast()).krate()]
+ })
+ }
+ &TyKind::Foreign(id) => {
+ let alias = from_foreign_def_id(id);
+ Some(if db.type_alias_data(alias).rustc_has_incoherent_inherent_impls {
+ db.incoherent_inherent_impl_crates(cur_crate, TyFingerprint::ForeignType(id))
+ } else {
+ smallvec![alias.module(db.upcast()).krate()]
+ })
+ }
+ TyKind::Dyn(_) => {
+ let trait_id = ty.dyn_trait()?;
+ Some(if db.trait_data(trait_id).rustc_has_incoherent_inherent_impls {
+ db.incoherent_inherent_impl_crates(cur_crate, TyFingerprint::Dyn(trait_id))
+ } else {
+ smallvec![trait_id.module(db.upcast()).krate()]
+ })
}
- TyKind::Dyn(_) => ty
- .dyn_trait()
- .and_then(|trait_| mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))),
// for primitives, there may be impls in various places (core and alloc
// mostly). We just check the whole crate graph for crates with impls
// (cached behind a query).
@@ -412,10 +429,11 @@ pub fn def_crates(
| TyKind::Str
| TyKind::Slice(_)
| TyKind::Array(..)
- | TyKind::Raw(..) => {
- Some(db.inherent_impl_crates(cur_crate, fp.expect("fingerprint for primitive")))
- }
- _ => return None,
+ | TyKind::Raw(..) => Some(db.incoherent_inherent_impl_crates(
+ cur_crate,
+ TyFingerprint::for_inherent_impl(ty).expect("fingerprint for primitive"),
+ )),
+ _ => None,
}
}
@@ -470,14 +488,15 @@ pub fn lang_names_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, Name)>
/// Look up the method with the given name.
pub(crate) fn lookup_method(
- ty: &Canonical<Ty>,
db: &dyn HirDatabase,
+ ty: &Canonical<Ty>,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: &Name,
-) -> Option<(ReceiverAdjustments, FunctionId)> {
- iterate_method_candidates(
+) -> Option<(ReceiverAdjustments, FunctionId, bool)> {
+ let mut not_visible = None;
+ let res = iterate_method_candidates(
ty,
db,
env,
@@ -485,11 +504,16 @@ pub(crate) fn lookup_method(
visible_from_module,
Some(name),
LookupMode::MethodCall,
- |adjustments, f| match f {
- AssocItemId::FunctionId(f) => Some((adjustments, f)),
+ |adjustments, f, visible| match f {
+ AssocItemId::FunctionId(f) if visible => Some((adjustments, f, true)),
+ AssocItemId::FunctionId(f) if not_visible.is_none() => {
+ not_visible = Some((adjustments, f, false));
+ None
+ }
_ => None,
},
- )
+ );
+ res.or(not_visible)
}
/// Whether we're looking up a dotted method call (like `v.len()`) or a path
@@ -601,7 +625,7 @@ pub(crate) fn iterate_method_candidates<T>(
visible_from_module: VisibleFromModule,
name: Option<&Name>,
mode: LookupMode,
- mut callback: impl FnMut(ReceiverAdjustments, AssocItemId) -> Option<T>,
+ mut callback: impl FnMut(ReceiverAdjustments, AssocItemId, bool) -> Option<T>,
) -> Option<T> {
let mut slot = None;
iterate_method_candidates_dyn(
@@ -612,9 +636,9 @@ pub(crate) fn iterate_method_candidates<T>(
visible_from_module,
name,
mode,
- &mut |adj, item| {
+ &mut |adj, item, visible| {
assert!(slot.is_none());
- if let Some(it) = callback(adj, item) {
+ if let Some(it) = callback(adj, item, visible) {
slot = Some(it);
return ControlFlow::Break(());
}
@@ -624,6 +648,30 @@ pub(crate) fn iterate_method_candidates<T>(
slot
}
+pub fn lookup_impl_const(
+ db: &dyn HirDatabase,
+ env: Arc<TraitEnvironment>,
+ const_id: ConstId,
+ subs: Substitution,
+) -> ConstId {
+ let trait_id = match const_id.lookup(db.upcast()).container {
+ ItemContainerId::TraitId(id) => id,
+ _ => return const_id,
+ };
+ let substitution = Substitution::from_iter(Interner, subs.iter(Interner));
+ let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution };
+
+ let const_data = db.const_data(const_id);
+ let name = match const_data.name.as_ref() {
+ Some(name) => name,
+ None => return const_id,
+ };
+
+ lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name)
+ .and_then(|assoc| if let AssocItemId::ConstId(id) = assoc { Some(id) } else { None })
+ .unwrap_or(const_id)
+}
+
/// Looks up the impl method that actually runs for the trait method `func`.
///
/// Returns `func` if it's not a method defined in a trait or the lookup failed.
@@ -645,15 +693,17 @@ pub fn lookup_impl_method(
};
let name = &db.function_data(func).name;
- lookup_impl_method_for_trait_ref(trait_ref, db, env, name).unwrap_or(func)
+ lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name)
+ .and_then(|assoc| if let AssocItemId::FunctionId(id) = assoc { Some(id) } else { None })
+ .unwrap_or(func)
}
-fn lookup_impl_method_for_trait_ref(
+fn lookup_impl_assoc_item_for_trait_ref(
trait_ref: TraitRef,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
name: &Name,
-) -> Option<FunctionId> {
+) -> Option<AssocItemId> {
let self_ty = trait_ref.self_type_parameter(Interner);
let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?;
let impls = db.trait_impls_in_deps(env.krate);
@@ -663,7 +713,15 @@ fn lookup_impl_method_for_trait_ref(
let impl_data = find_matching_impl(impls, table, trait_ref)?;
impl_data.items.iter().find_map(|it| match it {
- AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
+ AssocItemId::FunctionId(f) => {
+ (db.function_data(*f).name == *name).then_some(AssocItemId::FunctionId(*f))
+ }
+ AssocItemId::ConstId(c) => db
+ .const_data(*c)
+ .name
+ .as_ref()
+ .map(|n| *n == *name)
+ .and_then(|result| if result { Some(AssocItemId::ConstId(*c)) } else { None }),
_ => None,
})
}
@@ -719,7 +777,7 @@ pub fn iterate_path_candidates(
name,
LookupMode::Path,
// the adjustments are not relevant for path lookup
- &mut |_, id| callback(id),
+ &mut |_, id, _| callback(id),
)
}
@@ -731,7 +789,7 @@ pub fn iterate_method_candidates_dyn(
visible_from_module: VisibleFromModule,
name: Option<&Name>,
mode: LookupMode,
- callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+ callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
match mode {
LookupMode::MethodCall => {
@@ -795,7 +853,7 @@ fn iterate_method_candidates_with_autoref(
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
- mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+ mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) {
// don't try to resolve methods on unknown types
@@ -856,7 +914,7 @@ fn iterate_method_candidates_by_receiver(
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
- mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+ mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
let mut table = InferenceTable::new(db, env);
let receiver_ty = table.instantiate_canonical(receiver_ty.clone());
@@ -868,7 +926,7 @@ fn iterate_method_candidates_by_receiver(
while let Some((self_ty, _)) = autoderef.next() {
iterate_inherent_methods(
&self_ty,
- &mut autoderef.table,
+ autoderef.table,
name,
Some(&receiver_ty),
Some(receiver_adjustments.clone()),
@@ -883,7 +941,7 @@ fn iterate_method_candidates_by_receiver(
while let Some((self_ty, _)) = autoderef.next() {
iterate_trait_method_candidates(
&self_ty,
- &mut autoderef.table,
+ autoderef.table,
traits_in_scope,
name,
Some(&receiver_ty),
@@ -902,7 +960,7 @@ fn iterate_method_candidates_for_self_ty(
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
- mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+ mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
let mut table = InferenceTable::new(db, env);
let self_ty = table.instantiate_canonical(self_ty.clone());
@@ -933,7 +991,7 @@ fn iterate_trait_method_candidates(
name: Option<&Name>,
receiver_ty: Option<&Ty>,
receiver_adjustments: Option<ReceiverAdjustments>,
- callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+ callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
let db = table.db;
let env = table.trait_env.clone();
@@ -964,9 +1022,11 @@ fn iterate_trait_method_candidates(
for &(_, item) in data.items.iter() {
// Don't pass a `visible_from_module` down to `is_valid_candidate`,
// since only inherent methods should be included into visibility checking.
- if !is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
- continue;
- }
+ let visible = match is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
+ IsValidCandidate::Yes => true,
+ IsValidCandidate::NotVisible => false,
+ IsValidCandidate::No => continue,
+ };
if !known_implemented {
let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty);
if db.trait_solve(env.krate, goal.cast(Interner)).is_none() {
@@ -974,7 +1034,7 @@ fn iterate_trait_method_candidates(
}
}
known_implemented = true;
- callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
+ callback(receiver_adjustments.clone().unwrap_or_default(), item, visible)?;
}
}
ControlFlow::Continue(())
@@ -987,7 +1047,7 @@ fn iterate_inherent_methods(
receiver_ty: Option<&Ty>,
receiver_adjustments: Option<ReceiverAdjustments>,
visible_from_module: VisibleFromModule,
- callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+ callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
let db = table.db;
let env = table.trait_env.clone();
@@ -1076,7 +1136,7 @@ fn iterate_inherent_methods(
name: Option<&Name>,
receiver_ty: Option<&Ty>,
receiver_adjustments: Option<ReceiverAdjustments>,
- callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+ callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
traits: impl Iterator<Item = TraitId>,
) -> ControlFlow<()> {
let db = table.db;
@@ -1084,9 +1144,13 @@ fn iterate_inherent_methods(
let data = db.trait_data(t);
for &(_, item) in data.items.iter() {
// We don't pass `visible_from_module` as all trait items should be visible.
- if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
- callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
- }
+ let visible =
+ match is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
+ IsValidCandidate::Yes => true,
+ IsValidCandidate::NotVisible => false,
+ IsValidCandidate::No => continue,
+ };
+ callback(receiver_adjustments.clone().unwrap_or_default(), item, visible)?;
}
}
ControlFlow::Continue(())
@@ -1100,17 +1164,25 @@ fn iterate_inherent_methods(
receiver_ty: Option<&Ty>,
receiver_adjustments: Option<ReceiverAdjustments>,
visible_from_module: Option<ModuleId>,
- callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+ callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
let db = table.db;
let impls_for_self_ty = impls.for_self_ty(self_ty);
for &impl_def in impls_for_self_ty {
for &item in &db.impl_data(impl_def).items {
- if !is_valid_candidate(table, name, receiver_ty, item, self_ty, visible_from_module)
- {
- continue;
- }
- callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
+ let visible = match is_valid_candidate(
+ table,
+ name,
+ receiver_ty,
+ item,
+ self_ty,
+ visible_from_module,
+ ) {
+ IsValidCandidate::Yes => true,
+ IsValidCandidate::NotVisible => false,
+ IsValidCandidate::No => continue,
+ };
+ callback(receiver_adjustments.clone().unwrap_or_default(), item, visible)?;
}
}
ControlFlow::Continue(())
@@ -1139,7 +1211,7 @@ pub fn resolve_indexing_op(
macro_rules! check_that {
($cond:expr) => {
if !$cond {
- return false;
+ return IsValidCandidate::No;
}
};
}
@@ -1151,7 +1223,7 @@ fn is_valid_candidate(
item: AssocItemId,
self_ty: &Ty,
visible_from_module: Option<ModuleId>,
-) -> bool {
+) -> IsValidCandidate {
let db = table.db;
match item {
AssocItemId::FunctionId(m) => {
@@ -1162,31 +1234,37 @@ fn is_valid_candidate(
check_that!(receiver_ty.is_none());
check_that!(name.map_or(true, |n| data.name.as_ref() == Some(n)));
- check_that!(visible_from_module.map_or(true, |from_module| {
- let v = db.const_visibility(c).is_visible_from(db.upcast(), from_module);
- if !v {
+
+ if let Some(from_module) = visible_from_module {
+ if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) {
cov_mark::hit!(const_candidate_not_visible);
+ return IsValidCandidate::NotVisible;
}
- v
- }));
+ }
if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
let self_ty_matches = table.run_in_snapshot(|table| {
let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
.fill_with_inference_vars(table)
.build();
- table.unify(&expected_self_ty, &self_ty)
+ table.unify(&expected_self_ty, self_ty)
});
if !self_ty_matches {
cov_mark::hit!(const_candidate_self_type_mismatch);
- return false;
+ return IsValidCandidate::No;
}
}
- true
+ IsValidCandidate::Yes
}
- _ => false,
+ _ => IsValidCandidate::No,
}
}
+enum IsValidCandidate {
+ Yes,
+ No,
+ NotVisible,
+}
+
fn is_valid_fn_candidate(
table: &mut InferenceTable<'_>,
fn_id: FunctionId,
@@ -1194,19 +1272,17 @@ fn is_valid_fn_candidate(
receiver_ty: Option<&Ty>,
self_ty: &Ty,
visible_from_module: Option<ModuleId>,
-) -> bool {
+) -> IsValidCandidate {
let db = table.db;
let data = db.function_data(fn_id);
check_that!(name.map_or(true, |n| n == &data.name));
- check_that!(visible_from_module.map_or(true, |from_module| {
- let v = db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module);
- if !v {
+ if let Some(from_module) = visible_from_module {
+ if !db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module) {
cov_mark::hit!(autoderef_candidate_not_visible);
+ return IsValidCandidate::NotVisible;
}
- v
- }));
-
+ }
table.run_in_snapshot(|table| {
let container = fn_id.lookup(db.upcast()).container;
let (impl_subst, expect_self_ty) = match container {
@@ -1245,7 +1321,7 @@ fn is_valid_fn_candidate(
// We need to consider the bounds on the impl to distinguish functions of the same name
// for a type.
let predicates = db.generic_predicates(impl_id.into());
- predicates
+ let valid = predicates
.iter()
.map(|predicate| {
let (p, b) = predicate
@@ -1260,12 +1336,16 @@ fn is_valid_fn_candidate(
// It's ok to get ambiguity here, as we may not have enough information to prove
// obligations. We'll check if the user is calling the selected method properly
// later anyway.
- .all(|p| table.try_obligation(p.cast(Interner)).is_some())
+ .all(|p| table.try_obligation(p.cast(Interner)).is_some());
+ match valid {
+ true => IsValidCandidate::Yes,
+ false => IsValidCandidate::No,
+ }
} else {
// For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in
// `iterate_trait_method_candidates()`.
// For others, this function shouldn't be called.
- true
+ IsValidCandidate::Yes
}
})
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index ebbc54101..ba5d9c241 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -94,18 +94,19 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
types.insert(file_range, expected.trim_start_matches("type: ").to_string());
} else if expected.starts_with("expected") {
mismatches.insert(file_range, expected);
- } else if expected.starts_with("adjustments: ") {
+ } else if expected.starts_with("adjustments:") {
adjustments.insert(
file_range,
expected
- .trim_start_matches("adjustments: ")
+ .trim_start_matches("adjustments:")
+ .trim()
.split(',')
.map(|it| it.trim().to_string())
.filter(|it| !it.is_empty())
.collect(),
);
} else {
- panic!("unexpected annotation: {}", expected);
+ panic!("unexpected annotation: {expected}");
}
had_annotations = true;
}
@@ -176,17 +177,17 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
assert_eq!(actual, expected);
}
if let Some(expected) = adjustments.remove(&range) {
- if let Some(adjustments) = inference_result.expr_adjustments.get(&expr) {
- assert_eq!(
- expected,
- adjustments
- .iter()
- .map(|Adjustment { kind, .. }| format!("{:?}", kind))
- .collect::<Vec<_>>()
- );
- } else {
- panic!("expected {:?} adjustments, found none", expected);
- }
+ let adjustments = inference_result
+ .expr_adjustments
+ .get(&expr)
+ .map_or_else(Default::default, |it| &**it);
+ assert_eq!(
+ expected,
+ adjustments
+ .iter()
+ .map(|Adjustment { kind, .. }| format!("{kind:?}"))
+ .collect::<Vec<_>>()
+ );
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
index 7e3aecc2a..3e110abaf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
@@ -807,3 +807,37 @@ fn main() {
"#,
);
}
+
+#[test]
+fn adjust_comparison_arguments() {
+ check_no_mismatches(
+ r"
+//- minicore: eq
+struct Struct;
+impl core::cmp::PartialEq for Struct {
+ fn eq(&self, other: &Self) -> bool { true }
+}
+fn test() {
+ Struct == Struct;
+ // ^^^^^^ adjustments: Borrow(Ref(Not))
+ // ^^^^^^ adjustments: Borrow(Ref(Not))
+}",
+ );
+}
+
+#[test]
+fn adjust_assign_lhs() {
+ check_no_mismatches(
+ r"
+//- minicore: add
+struct Struct;
+impl core::ops::AddAssign for Struct {
+ fn add_assign(&mut self, other: Self) {}
+}
+fn test() {
+ Struct += Struct;
+ // ^^^^^^ adjustments: Borrow(Ref(Mut))
+ // ^^^^^^ adjustments:
+}",
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
index 3e08e83e8..073d6d9be 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
@@ -24,7 +24,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
db.infer(def);
});
});
- assert!(format!("{:?}", events).contains("infer"))
+ assert!(format!("{events:?}").contains("infer"))
}
let new_text = "
@@ -46,6 +46,6 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
db.infer(def);
});
});
- assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events)
+ assert!(!format!("{events:?}").contains("infer"), "{events:#?}")
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
index b3adafaaf..8b75ec842 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
@@ -849,7 +849,7 @@ fn main() {
//^^^^^^^^^^^^^^^^^ RegisterBlock
}
"#;
- let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data);
+ let fixture = format!("{fixture}\n//- /foo.rs\n{data}");
{
let _b = bench("include macro");
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 5d76d185f..6c7a53299 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
@@ -1867,3 +1867,53 @@ fn g<T: Trait>(a: T) {
"#,
);
}
+
+#[test]
+fn incoherent_impls() {
+ check(
+ r#"
+//- minicore: error, send
+pub struct Box<T>(T);
+use core::error::Error;
+
+#[rustc_allow_incoherent_impl]
+impl dyn Error {
+ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
+ loop {}
+ }
+}
+#[rustc_allow_incoherent_impl]
+impl dyn Error + Send {
+ /// Attempts to downcast the box to a concrete type.
+ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
+ let err: Box<dyn Error> = self;
+ // ^^^^ expected Box<dyn Error>, got Box<dyn Error + Send>
+ // FIXME, type mismatch should not occur
+ <dyn Error>::downcast(err).map_err(|_| loop {})
+ //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error>) -> Result<Box<{unknown}>, Box<dyn Error>>
+ }
+}
+"#,
+ );
+}
+
+#[test]
+fn fallback_private_methods() {
+ check(
+ r#"
+mod module {
+ pub struct Struct;
+
+ impl Struct {
+ fn func(&self) {}
+ }
+}
+
+fn foo() {
+ let s = module::Struct;
+ s.func();
+ //^^^^^^^^ type: ()
+}
+"#,
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
index 74de33117..9333e2693 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
@@ -1080,3 +1080,15 @@ fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {}
"#,
);
}
+
+#[test]
+fn var_args() {
+ check_types(
+ r#"
+#[lang = "va_list"]
+pub struct VaListImpl<'f>;
+fn my_fn(foo: ...) {}
+ //^^^ VaListImpl
+"#,
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index 4e4639745..de6ae7fff 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -1723,3 +1723,24 @@ fn bar() -> ControlFlow<(), ()> {
"#,
);
}
+
+#[test]
+fn assoc_type_shorthand_with_gats_in_binders() {
+ // c.f. test `issue_4885()`
+ check_no_mismatches(
+ r#"
+trait Gats {
+ type Assoc<T>;
+}
+trait Foo<T> {}
+
+struct Bar<'a, B: Gats, A> {
+ field: &'a dyn Foo<B::Assoc<A>>,
+}
+
+fn foo(b: Bar) {
+ let _ = b.field;
+}
+"#,
+ );
+}
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 d7431443b..146145523 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
@@ -2064,17 +2064,17 @@ fn fn_pointer_return() {
fn block_modifiers_smoke_test() {
check_infer(
r#"
-//- minicore: future
+//- minicore: future, try
async fn main() {
let x = unsafe { 92 };
let y = async { async { () }.await };
- let z = try { () };
+ let z: core::ops::ControlFlow<(), _> = try { () };
let w = const { 92 };
let t = 'a: { 92 };
}
"#,
expect![[r#"
- 16..162 '{ ...2 }; }': ()
+ 16..193 '{ ...2 }; }': ()
26..27 'x': i32
30..43 'unsafe { 92 }': i32
30..43 'unsafe { 92 }': i32
@@ -2086,17 +2086,17 @@ async fn main() {
65..77 'async { () }': impl Future<Output = ()>
65..83 'async ....await': ()
73..75 '()': ()
- 95..96 'z': {unknown}
- 99..109 'try { () }': ()
- 99..109 'try { () }': {unknown}
- 105..107 '()': ()
- 119..120 'w': i32
- 123..135 'const { 92 }': i32
- 123..135 'const { 92 }': i32
- 131..133 '92': i32
- 145..146 't': i32
- 149..159 ''a: { 92 }': i32
- 155..157 '92': i32
+ 95..96 'z': ControlFlow<(), ()>
+ 130..140 'try { () }': ()
+ 130..140 'try { () }': ControlFlow<(), ()>
+ 136..138 '()': ()
+ 150..151 'w': i32
+ 154..166 'const { 92 }': i32
+ 154..166 'const { 92 }': i32
+ 162..164 '92': i32
+ 176..177 't': i32
+ 180..190 ''a: { 92 }': i32
+ 186..188 '92': i32
"#]],
)
}
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 3d7194b6f..d01fe0632 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
@@ -1389,6 +1389,22 @@ fn foo<const C: u8, T>() -> (impl FnOnce(&str, T), impl Trait<u8>) {
}
#[test]
+fn return_pos_impl_trait_in_projection() {
+ // Note that the unused type param `X` is significant; see #13307.
+ check_no_mismatches(
+ r#"
+//- minicore: sized
+trait Future { type Output; }
+impl Future for () { type Output = i32; }
+type Foo<F> = (<F as Future>::Output, F);
+fn foo<X>() -> Foo<impl Future<Output = ()>> {
+ (0, ())
+}
+"#,
+ )
+}
+
+#[test]
fn dyn_trait() {
check_infer(
r#"
@@ -4084,3 +4100,68 @@ where
"#,
);
}
+
+#[test]
+fn bin_op_with_scalar_fallback() {
+ // Extra impls are significant so that chalk doesn't give us definite guidances.
+ check_types(
+ r#"
+//- minicore: add
+use core::ops::Add;
+
+struct Vec2<T>(T, T);
+
+impl Add for Vec2<i32> {
+ type Output = Self;
+ fn add(self, rhs: Self) -> Self::Output { loop {} }
+}
+impl Add for Vec2<u32> {
+ type Output = Self;
+ fn add(self, rhs: Self) -> Self::Output { loop {} }
+}
+impl Add for Vec2<f32> {
+ type Output = Self;
+ fn add(self, rhs: Self) -> Self::Output { loop {} }
+}
+impl Add for Vec2<f64> {
+ type Output = Self;
+ fn add(self, rhs: Self) -> Self::Output { loop {} }
+}
+
+fn test() {
+ let a = Vec2(1, 2);
+ let b = Vec2(3, 4);
+ let c = a + b;
+ //^ Vec2<i32>
+ let a = Vec2(1., 2.);
+ let b = Vec2(3., 4.);
+ let c = a + b;
+ //^ Vec2<f64>
+}
+"#,
+ );
+}
+
+#[test]
+fn trait_method_with_scalar_fallback() {
+ check_types(
+ r#"
+trait Trait {
+ type Output;
+ fn foo(&self) -> Self::Output;
+}
+impl<T> Trait for T {
+ type Output = T;
+ fn foo(&self) -> Self::Output { loop {} }
+}
+fn test() {
+ let a = 42;
+ let b = a.foo();
+ //^ i32
+ let a = 3.14;
+ let b = a.foo();
+ //^ f64
+}
+"#,
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs
index 92711a24f..b7e6ee674 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs
@@ -67,12 +67,12 @@ impl DebugContext<'_> {
let trait_ref = projection_ty.trait_ref(self.0);
let trait_params = trait_ref.substitution.as_slice(Interner);
let self_ty = trait_ref.self_type_parameter(Interner);
- write!(fmt, "<{:?} as {}", self_ty, trait_name)?;
+ write!(fmt, "<{self_ty:?} as {trait_name}")?;
if trait_params.len() > 1 {
write!(
fmt,
"<{}>",
- trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
+ trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))),
)?;
}
write!(fmt, ">::{}", type_alias_data.name)?;
@@ -83,7 +83,7 @@ impl DebugContext<'_> {
write!(
fmt,
"<{}>",
- proj_params.iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
+ proj_params.iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))),
)?;
}
@@ -105,9 +105,9 @@ impl DebugContext<'_> {
}
};
match def {
- CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name),
+ CallableDefId::FunctionId(_) => write!(fmt, "{{fn {name}}}"),
CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {
- write!(fmt, "{{ctor {}}}", name)
+ write!(fmt, "{{ctor {name}}}")
}
}
}
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 c425f35ac..778a6b820 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
@@ -18,7 +18,7 @@ use crate::{
};
/// This controls how much 'time' we give the Chalk solver before giving up.
-const CHALK_SOLVER_FUEL: i32 = 100;
+const CHALK_SOLVER_FUEL: i32 = 1000;
#[derive(Debug, Copy, Clone)]
pub(crate) struct ChalkContext<'a> {
@@ -55,13 +55,10 @@ impl TraitEnvironment {
}
}
- pub fn traits_in_scope_from_clauses<'a>(
- &'a self,
- ty: Ty,
- ) -> impl Iterator<Item = TraitId> + 'a {
+ pub fn traits_in_scope_from_clauses(&self, ty: Ty) -> impl Iterator<Item = TraitId> + '_ {
self.traits_from_clauses
.iter()
- .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then(|| *trait_id))
+ .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then_some(*trait_id))
}
}
@@ -130,7 +127,7 @@ fn solve(
let mut solve = || {
let _ctx = if is_chalk_debug() || is_chalk_print() {
- Some(panic_context::enter(format!("solving {:?}", goal)))
+ Some(panic_context::enter(format!("solving {goal:?}")))
} else {
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 e54bcb421..9893566bd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -17,7 +17,7 @@ use hir_def::{
ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId,
TypeOrConstParamId, TypeParamId,
};
-use hir_expand::name::{known, Name};
+use hir_expand::name::Name;
use itertools::Either;
use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec};
@@ -184,9 +184,7 @@ pub(crate) struct Generics {
}
impl Generics {
- pub(crate) fn iter_id<'a>(
- &'a self,
- ) -> impl Iterator<Item = Either<TypeParamId, ConstParamId>> + 'a {
+ pub(crate) fn iter_id(&self) -> impl Iterator<Item = Either<TypeParamId, ConstParamId>> + '_ {
self.iter().map(|(id, data)| match data {
TypeOrConstParamData::TypeParamData(_) => Either::Left(TypeParamId::from_unchecked(id)),
TypeOrConstParamData::ConstParamData(_) => {
@@ -216,9 +214,9 @@ impl Generics {
}
/// Iterator over types and const params of parent.
- pub(crate) fn iter_parent<'a>(
- &'a self,
- ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
+ pub(crate) fn iter_parent(
+ &self,
+ ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &TypeOrConstParamData)> {
self.parent_generics().into_iter().flat_map(|it| {
let to_toc_id =
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p);
@@ -335,54 +333,18 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
// Function in an `extern` block are always unsafe to call, except when it has
// `"rust-intrinsic"` ABI there are a few exceptions.
let id = block.lookup(db.upcast()).id;
- !matches!(
- id.item_tree(db.upcast())[id.value].abi.as_deref(),
- Some("rust-intrinsic") if !is_intrinsic_fn_unsafe(&data.name)
- )
+
+ let is_intrinsic =
+ id.item_tree(db.upcast())[id.value].abi.as_deref() == Some("rust-intrinsic");
+
+ if is_intrinsic {
+ // Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
+ !data.attrs.by_key("rustc_safe_intrinsic").exists()
+ } else {
+ // Extern items are always unsafe
+ true
+ }
}
_ => false,
}
}
-
-/// Returns `true` if the given intrinsic is unsafe to call, or false otherwise.
-fn is_intrinsic_fn_unsafe(name: &Name) -> bool {
- // Should be kept in sync with https://github.com/rust-lang/rust/blob/532d2b14c05f9bc20b2d27cbb5f4550d28343a36/compiler/rustc_typeck/src/check/intrinsic.rs#L72-L106
- ![
- known::abort,
- known::add_with_overflow,
- known::bitreverse,
- known::black_box,
- known::bswap,
- known::caller_location,
- known::ctlz,
- known::ctpop,
- known::cttz,
- known::discriminant_value,
- known::forget,
- known::likely,
- known::maxnumf32,
- known::maxnumf64,
- known::min_align_of,
- known::minnumf32,
- known::minnumf64,
- known::mul_with_overflow,
- known::needs_drop,
- known::ptr_guaranteed_eq,
- known::ptr_guaranteed_ne,
- known::rotate_left,
- known::rotate_right,
- known::rustc_peek,
- known::saturating_add,
- known::saturating_sub,
- known::size_of,
- known::sub_with_overflow,
- known::type_id,
- known::type_name,
- known::unlikely,
- known::variant_count,
- known::wrapping_add,
- known::wrapping_mul,
- known::wrapping_sub,
- ]
- .contains(name)
-}