summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-ty
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /src/tools/rust-analyzer/crates/hir-ty
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-ty')
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs43
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs108
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs143
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs86
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs31
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs157
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tls.rs28
17 files changed, 580 insertions, 166 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index ed13275ba..a1d6835bf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
description = "TBD"
license = "MIT OR Apache-2.0"
edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
[lib]
doctest = false
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index e2099d7e5..996b42f5b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -11,9 +11,9 @@ use syntax::SmolStr;
use crate::{
db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
- from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId,
- CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause,
- Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
+ from_placeholder_idx, to_chalk_trait_id, utils::generics, AdtId, AliasEq, AliasTy, Binders,
+ CallableDefId, CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy,
+ QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
};
pub trait TyExt {
@@ -338,10 +338,13 @@ pub trait ProjectionTyExt {
impl ProjectionTyExt for ProjectionTy {
fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
- TraitRef {
- trait_id: to_chalk_trait_id(self.trait_(db)),
- substitution: self.substitution.clone(),
- }
+ // FIXME: something like `Split` trait from chalk-solve might be nice.
+ let generics = generics(db.upcast(), from_assoc_type_id(self.associated_ty_id).into());
+ let substitution = Substitution::from_iter(
+ Interner,
+ self.substitution.iter(Interner).skip(generics.len_self()),
+ );
+ TraitRef { trait_id: to_chalk_trait_id(self.trait_(db)), substitution }
}
fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
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 0221f922f..a22a4b170 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -289,16 +289,18 @@ impl HirDisplay for ProjectionTy {
return write!(f, "{}", TYPE_HINT_TRUNCATION);
}
- let trait_ = f.db.trait_data(self.trait_(f.db));
+ let trait_ref = self.trait_ref(f.db);
write!(f, "<")?;
- self.self_type_parameter(f.db).hir_fmt(f)?;
- write!(f, " as {}", trait_.name)?;
- if self.substitution.len(Interner) > 1 {
+ fmt_trait_ref(&trait_ref, f, true)?;
+ write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
+ let proj_params_count =
+ self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
+ let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
+ if !proj_params.is_empty() {
write!(f, "<")?;
- f.write_joined(&self.substitution.as_slice(Interner)[1..], ", ")?;
+ f.write_joined(proj_params, ", ")?;
write!(f, ">")?;
}
- write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
Ok(())
}
}
@@ -641,9 +643,12 @@ impl HirDisplay for Ty {
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
if f.display_target.is_test() {
write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
+ // Note that the generic args for the associated type come before those for the
+ // trait (including the self type).
+ // FIXME: reconsider the generic args order upon formatting?
if parameters.len(Interner) > 0 {
write!(f, "<")?;
- f.write_joined(&*parameters.as_slice(Interner), ", ")?;
+ f.write_joined(parameters.as_slice(Interner), ", ")?;
write!(f, ">")?;
}
} else {
@@ -972,9 +977,20 @@ fn write_bounds_like_dyn_trait(
angle_open = true;
}
if let AliasTy::Projection(proj) = alias {
- let type_alias =
- f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
- write!(f, "{} = ", type_alias.name)?;
+ let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
+ let type_alias = f.db.type_alias_data(assoc_ty_id);
+ write!(f, "{}", type_alias.name)?;
+
+ let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
+ if proj_arg_count > 0 {
+ write!(f, "<")?;
+ f.write_joined(
+ &proj.substitution.as_slice(Interner)[..proj_arg_count],
+ ", ",
+ )?;
+ write!(f, ">")?;
+ }
+ write!(f, " = ")?;
}
ty.hir_fmt(f)?;
}
@@ -1171,8 +1187,11 @@ impl HirDisplay for TypeRef {
inner.hir_fmt(f)?;
write!(f, "]")?;
}
- TypeRef::Fn(parameters, is_varargs) => {
+ &TypeRef::Fn(ref parameters, is_varargs, is_unsafe) => {
// FIXME: Function pointer qualifiers.
+ if is_unsafe {
+ write!(f, "unsafe ")?;
+ }
write!(f, "fn(")?;
if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
for index in 0..function_parameters.len() {
@@ -1187,7 +1206,7 @@ impl HirDisplay for TypeRef {
write!(f, ", ")?;
}
}
- if *is_varargs {
+ if is_varargs {
write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
}
write!(f, ")")?;
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 0efff651c..0b3c23f57 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -1020,7 +1020,7 @@ impl Expectation {
/// The primary use case is where the expected type is a fat pointer,
/// like `&[isize]`. For example, consider the following statement:
///
- /// let x: &[isize] = &[1, 2, 3];
+ /// let x: &[isize] = &[1, 2, 3];
///
/// In this case, the expected type for the `&[1, 2, 3]` expression is
/// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
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 f56108b26..b1f4de826 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
@@ -85,6 +85,7 @@ impl<'a> InferenceContext<'a> {
let ty = match &self.body[tgt_expr] {
Expr::Missing => self.err_ty(),
&Expr::If { condition, then_branch, else_branch } => {
+ let expected = &expected.adjust_for_branches(&mut self.table);
self.infer_expr(
condition,
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
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 7a4754cdc..ebe9d6fb5 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
@@ -157,7 +157,7 @@ impl<'a> InferenceContext<'a> {
remaining_segments_for_ty,
true,
);
- if let TyKind::Error = ty.kind(Interner) {
+ if ty.is_unknown() {
return None;
}
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 b00e3216b..12f45f00f 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
@@ -340,8 +340,8 @@ impl<'a> InferenceTable<'a> {
self.resolve_with_fallback(t, &|_, _, d, _| d)
}
- /// Unify two types and register new trait goals that arise from that.
- pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
+ /// 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) {
Ok(r) => r,
Err(_) => return false,
@@ -350,9 +350,13 @@ impl<'a> InferenceTable<'a> {
true
}
- /// Unify two types and return new trait goals arising from it, so the
+ /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the
/// caller needs to deal with them.
- pub(crate) fn try_unify<T: Zip<Interner>>(&mut self, t1: &T, t2: &T) -> InferResult<()> {
+ pub(crate) fn try_unify<T: ?Sized + Zip<Interner>>(
+ &mut self,
+ t1: &T,
+ t2: &T,
+ ) -> InferResult<()> {
match self.var_unification_table.relate(
Interner,
&self.db,
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 c4b700cbc..39514fc44 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -38,10 +38,12 @@ use std::sync::Arc;
use chalk_ir::{
fold::{Shift, TypeFoldable},
interner::HasInterner,
- NoSolution,
+ NoSolution, UniverseIndex,
};
use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
+use hir_expand::name;
use itertools::Either;
+use traits::FnTrait;
use utils::Generics;
use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
@@ -51,7 +53,7 @@ pub use builder::{ParamKind, TyBuilder};
pub use chalk_ext::*;
pub use infer::{
could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic,
- InferenceResult,
+ InferenceResult, OverloadedDeref, PointerCast,
};
pub use interner::Interner;
pub use lower::{
@@ -81,7 +83,20 @@ pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
pub type VariableKind = chalk_ir::VariableKind<Interner>;
pub type VariableKinds = chalk_ir::VariableKinds<Interner>;
pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
+/// Represents generic parameters and an item bound by them. When the item has parent, the binders
+/// also contain the generic parameters for its parent. See chalk's documentation for details.
+///
+/// One thing to keep in mind when working with `Binders` (and `Substitution`s, which represent
+/// generic arguments) in rust-analyzer is that the ordering within *is* significant - the generic
+/// parameters/arguments for an item MUST come before those for its parent. This is to facilitate
+/// the integration with chalk-solve, which mildly puts constraints as such. See #13335 for its
+/// motivation in detail.
pub type Binders<T> = chalk_ir::Binders<T>;
+/// Interned list of generic arguments for an item. When an item has parent, the `Substitution` for
+/// it contains generic arguments for both its parent and itself. See chalk's documentation for
+/// details.
+///
+/// See `Binders` for the constraint on the ordering.
pub type Substitution = chalk_ir::Substitution<Interner>;
pub type GenericArg = chalk_ir::GenericArg<Interner>;
pub type GenericArgData = chalk_ir::GenericArgData<Interner>;
@@ -124,14 +139,6 @@ pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
pub type Guidance = chalk_solve::Guidance<Interner>;
pub type WhereClause = chalk_ir::WhereClause<Interner>;
-// FIXME: get rid of this
-pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
- Substitution::from_iter(
- Interner,
- s.as_slice(Interner)[..std::cmp::min(s.len(Interner), n)].iter().cloned(),
- )
-}
-
/// Return an index of a parameter in the generic type parameter list by it's id.
pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
generics(db.upcast(), id.parent).param_idx(id)
@@ -203,6 +210,7 @@ pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
pub struct CallableSig {
params_and_return: Arc<[Ty]>,
is_varargs: bool,
+ safety: Safety,
}
has_interner!(CallableSig);
@@ -211,9 +219,14 @@ has_interner!(CallableSig);
pub type PolyFnSig = Binders<CallableSig>;
impl CallableSig {
- pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> CallableSig {
+ pub fn from_params_and_return(
+ mut params: Vec<Ty>,
+ ret: Ty,
+ is_varargs: bool,
+ safety: Safety,
+ ) -> CallableSig {
params.push(ret);
- CallableSig { params_and_return: params.into(), is_varargs }
+ CallableSig { params_and_return: params.into(), is_varargs, safety }
}
pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
@@ -230,13 +243,14 @@ impl CallableSig {
.map(|arg| arg.assert_ty_ref(Interner).clone())
.collect(),
is_varargs: fn_ptr.sig.variadic,
+ safety: fn_ptr.sig.safety,
}
}
pub fn to_fn_ptr(&self) -> FnPointer {
FnPointer {
num_binders: 0,
- sig: FnSig { abi: (), safety: Safety::Safe, variadic: self.is_varargs },
+ sig: FnSig { abi: (), safety: self.safety, variadic: self.is_varargs },
substitution: FnSubst(Substitution::from_iter(
Interner,
self.params_and_return.iter().cloned(),
@@ -261,7 +275,11 @@ impl TypeFoldable<Interner> for CallableSig {
) -> Result<Self, E> {
let vec = self.params_and_return.to_vec();
let folded = vec.try_fold_with(folder, outer_binder)?;
- Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
+ Ok(CallableSig {
+ params_and_return: folded.into(),
+ is_varargs: self.is_varargs,
+ safety: self.safety,
+ })
}
}
@@ -382,7 +400,6 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold
pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T>
where
T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + Clone,
- T: HasInterner<Interner = Interner>,
{
use chalk_ir::{
fold::{FallibleTypeFolder, TypeSuperFoldable},
@@ -504,3 +521,64 @@ where
});
Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
}
+
+pub fn callable_sig_from_fnonce(
+ self_ty: &Ty,
+ env: Arc<TraitEnvironment>,
+ db: &dyn HirDatabase,
+) -> Option<CallableSig> {
+ let krate = env.krate;
+ 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 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();
+
+ let ret_ty = db.normalize_projection(projection, env);
+
+ Some(CallableSig::from_params_and_return(params, ret_ty.clone(), 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 223d705b1..baf9842d5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -227,13 +227,17 @@ impl<'a> TyLoweringContext<'a> {
.intern(Interner)
}
TypeRef::Placeholder => TyKind::Error.intern(Interner),
- TypeRef::Fn(params, is_varargs) => {
+ &TypeRef::Fn(ref params, variadic, is_unsafe) => {
let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr)))
});
TyKind::Function(FnPointer {
num_binders: 0, // FIXME lower `for<'a> fn()` correctly
- sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs },
+ sig: FnSig {
+ abi: (),
+ safety: if is_unsafe { Safety::Unsafe } else { Safety::Safe },
+ variadic,
+ },
substitution: FnSubst(substs),
})
.intern(Interner)
@@ -447,12 +451,31 @@ impl<'a> TyLoweringContext<'a> {
.db
.trait_data(trait_ref.hir_trait_id())
.associated_type_by_name(segment.name);
+
match found {
Some(associated_ty) => {
- // FIXME handle type parameters on the segment
+ // 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
+ // this point (`trait_ref.substitution`).
+ let substitution = self.substs_from_path_segment(
+ segment,
+ Some(associated_ty.into()),
+ false,
+ None,
+ );
+ let len_self =
+ generics(self.db.upcast(), associated_ty.into()).len_self();
+ let substitution = Substitution::from_iter(
+ Interner,
+ substitution
+ .iter(Interner)
+ .take(len_self)
+ .chain(trait_ref.substitution.iter(Interner)),
+ );
TyKind::Alias(AliasTy::Projection(ProjectionTy {
associated_ty_id: to_assoc_type_id(associated_ty),
- substitution: trait_ref.substitution,
+ substitution,
}))
.intern(Interner)
}
@@ -590,36 +613,48 @@ impl<'a> TyLoweringContext<'a> {
res,
Some(segment.name.clone()),
move |name, t, associated_ty| {
- if name == segment.name {
- 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(),
- self.resolver
- .generic_def()
- .expect("there should be generics if there's a generic param"),
- );
- let s = generics.placeholder_subst(self.db);
- s.apply(t.substitution.clone(), Interner)
- }
- ParamLoweringMode::Variable => t.substitution.clone(),
- };
- // 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);
- // FIXME handle type parameters on the segment
- Some(
- TyKind::Alias(AliasTy::Projection(ProjectionTy {
- associated_ty_id: to_assoc_type_id(associated_ty),
- substitution: substs,
- }))
- .intern(Interner),
- )
- } else {
- None
+ if name != segment.name {
+ return None;
}
+
+ // 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
+ // this point (`t.substitution`).
+ let substs = self.substs_from_path_segment(
+ segment.clone(),
+ Some(associated_ty.into()),
+ false,
+ None,
+ );
+
+ let len_self = generics(self.db.upcast(), associated_ty.into()).len_self();
+
+ let substs = Substitution::from_iter(
+ Interner,
+ substs.iter(Interner).take(len_self).chain(t.substitution.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),
+ substitution: substs,
+ }))
+ .intern(Interner),
+ )
},
);
@@ -777,7 +812,15 @@ impl<'a> TyLoweringContext<'a> {
// handle defaults. In expression or pattern path segments without
// explicitly specified type arguments, missing type arguments are inferred
// (i.e. defaults aren't used).
- if !infer_args || had_explicit_args {
+ // Generic parameters for associated types are not supposed to have defaults, so we just
+ // ignore them.
+ let is_assoc_ty = if let GenericDefId::TypeAliasId(id) = def {
+ let container = id.lookup(self.db.upcast()).container;
+ matches!(container, ItemContainerId::TraitId(_))
+ } else {
+ false
+ };
+ if !is_assoc_ty && (!infer_args || had_explicit_args) {
let defaults = self.db.generic_defaults(def);
assert_eq!(total_len, defaults.len());
let parent_from = item_len - substs.len();
@@ -966,9 +1009,28 @@ impl<'a> TyLoweringContext<'a> {
None => return SmallVec::new(),
Some(t) => t,
};
+ // 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
+ // this point (`super_trait_ref.substitution`).
+ let substitution = self.substs_from_path_segment(
+ // FIXME: This is hack. We shouldn't really build `PathSegment` directly.
+ PathSegment { name: &binding.name, args_and_bindings: binding.args.as_deref() },
+ Some(associated_ty.into()),
+ false, // this is not relevant
+ Some(super_trait_ref.self_type_parameter(Interner)),
+ );
+ let self_params = generics(self.db.upcast(), associated_ty.into()).len_self();
+ let substitution = Substitution::from_iter(
+ Interner,
+ substitution
+ .iter(Interner)
+ .take(self_params)
+ .chain(super_trait_ref.substitution.iter(Interner)),
+ );
let projection_ty = ProjectionTy {
associated_ty_id: to_assoc_type_id(associated_ty),
- substitution: super_trait_ref.substitution,
+ substitution,
};
let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity(
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
@@ -1515,7 +1577,12 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
.with_type_param_mode(ParamLoweringMode::Variable);
let ret = ctx_ret.lower_ty(&data.ret_type);
let generics = generics(db.upcast(), def.into());
- let sig = CallableSig::from_params_and_return(params, ret, data.is_varargs());
+ let sig = CallableSig::from_params_and_return(
+ params,
+ ret,
+ data.is_varargs(),
+ if data.has_unsafe_kw() { Safety::Unsafe } else { Safety::Safe },
+ );
make_binders(db, &generics, sig)
}
@@ -1559,7 +1626,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
- Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
+ Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe))
}
/// Build the type of a tuple struct constructor.
@@ -1586,7 +1653,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders();
- Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
+ Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe))
}
/// Build the type of a tuple enum variant constructor.
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 3a1a3f4fd..8bcfa2728 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
@@ -22,10 +22,10 @@ use crate::{
from_foreign_def_id,
infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
primitive::{FloatTy, IntTy, UintTy},
- static_lifetime,
+ static_lifetime, to_chalk_trait_id,
utils::all_super_traits,
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
- Scalar, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
+ Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
};
/// This is used as a key for indexing impls.
@@ -541,7 +541,7 @@ pub struct ReceiverAdjustments {
impl ReceiverAdjustments {
pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec<Adjustment>) {
- let mut ty = ty;
+ let mut ty = table.resolve_ty_shallow(&ty);
let mut adjust = Vec::new();
for _ in 0..self.autoderefs {
match autoderef::autoderef_step(table, ty.clone()) {
@@ -624,52 +624,76 @@ pub(crate) fn iterate_method_candidates<T>(
slot
}
+/// 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.
pub fn lookup_impl_method(
- self_ty: &Ty,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
- trait_: TraitId,
+ func: FunctionId,
+ fn_subst: Substitution,
+) -> FunctionId {
+ let trait_id = match func.lookup(db.upcast()).container {
+ ItemContainerId::TraitId(id) => id,
+ _ => return func,
+ };
+ let trait_params = db.generic_params(trait_id.into()).type_or_consts.len();
+ let fn_params = fn_subst.len(Interner) - trait_params;
+ let trait_ref = TraitRef {
+ trait_id: to_chalk_trait_id(trait_id),
+ substitution: Substitution::from_iter(Interner, fn_subst.iter(Interner).skip(fn_params)),
+ };
+
+ let name = &db.function_data(func).name;
+ lookup_impl_method_for_trait_ref(trait_ref, db, env, name).unwrap_or(func)
+}
+
+fn lookup_impl_method_for_trait_ref(
+ trait_ref: TraitRef,
+ db: &dyn HirDatabase,
+ env: Arc<TraitEnvironment>,
name: &Name,
) -> Option<FunctionId> {
- let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?;
- let trait_impls = db.trait_impls_in_deps(env.krate);
- let impls = trait_impls.for_trait_and_self_ty(trait_, self_ty_fp);
- let mut table = InferenceTable::new(db, env.clone());
- find_matching_impl(impls, &mut table, &self_ty).and_then(|data| {
- data.items.iter().find_map(|it| match it {
- AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
- _ => None,
- })
+ 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);
+ let impls = impls.for_trait_and_self_ty(trait_ref.hir_trait_id(), self_ty_fp);
+
+ let table = InferenceTable::new(db, env);
+
+ let impl_data = find_matching_impl(impls, table, trait_ref)?;
+ impl_data.items.iter().find_map(|it| match it {
+ AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
+ _ => None,
})
}
fn find_matching_impl(
mut impls: impl Iterator<Item = ImplId>,
- table: &mut InferenceTable<'_>,
- self_ty: &Ty,
+ mut table: InferenceTable<'_>,
+ actual_trait_ref: TraitRef,
) -> Option<Arc<ImplData>> {
let db = table.db;
loop {
let impl_ = impls.next()?;
let r = table.run_in_snapshot(|table| {
let impl_data = db.impl_data(impl_);
- let substs =
+ let impl_substs =
TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
- let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
-
- table
- .unify(self_ty, &impl_ty)
- .then(|| {
- let wh_goals =
- crate::chalk_db::convert_where_clauses(db, impl_.into(), &substs)
- .into_iter()
- .map(|b| b.cast(Interner));
+ let trait_ref = db
+ .impl_trait(impl_)
+ .expect("non-trait method in find_matching_impl")
+ .substitute(Interner, &impl_substs);
- let goal = crate::Goal::all(Interner, wh_goals);
+ if !table.unify(&trait_ref, &actual_trait_ref) {
+ return None;
+ }
- table.try_obligation(goal).map(|_| impl_data)
- })
- .flatten()
+ let wcs = crate::chalk_db::convert_where_clauses(db, impl_.into(), &impl_substs)
+ .into_iter()
+ .map(|b| b.cast(Interner));
+ let goal = crate::Goal::all(Interner, wcs);
+ table.try_obligation(goal).map(|_| impl_data)
});
if r.is_some() {
break r;
@@ -1214,7 +1238,7 @@ fn is_valid_fn_candidate(
let expected_receiver =
sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
- check_that!(table.unify(&receiver_ty, &expected_receiver));
+ check_that!(table.unify(receiver_ty, &expected_receiver));
}
if let ItemContainerId::ImplId(impl_id) = container {
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 d301595bc..7e3aecc2a 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
@@ -123,6 +123,23 @@ fn test() {
}
#[test]
+fn if_else_adjust_for_branches_discard_type_var() {
+ check_no_mismatches(
+ r#"
+fn test() {
+ let f = || {
+ if true {
+ &""
+ } else {
+ ""
+ }
+ };
+}
+"#,
+ );
+}
+
+#[test]
fn match_first_coerce() {
check_no_mismatches(
r#"
@@ -183,6 +200,22 @@ fn test() {
}
#[test]
+fn match_adjust_for_branches_discard_type_var() {
+ check_no_mismatches(
+ r#"
+fn test() {
+ let f = || {
+ match 0i32 {
+ 0i32 => &"",
+ _ => "",
+ }
+ };
+}
+"#,
+ );
+}
+
+#[test]
fn return_coerce_unknown() {
check_types(
r"
@@ -357,7 +390,7 @@ fn test() {
let f: fn(u32) -> isize = foo;
// ^^^ adjustments: Pointer(ReifyFnPointer)
let f: unsafe fn(u32) -> isize = foo;
- // ^^^ adjustments: Pointer(ReifyFnPointer)
+ // ^^^ adjustments: Pointer(ReifyFnPointer), Pointer(UnsafeFnPointer)
}",
);
}
@@ -388,7 +421,10 @@ fn coerce_closure_to_fn_ptr() {
check_no_mismatches(
r"
fn test() {
- let f: fn(u32) -> isize = |x| { 1 };
+ let f: fn(u32) -> u32 = |x| x;
+ // ^^^^^ adjustments: Pointer(ClosureFnPointer(Safe))
+ let f: unsafe fn(u32) -> u32 = |x| x;
+ // ^^^^^ adjustments: Pointer(ClosureFnPointer(Unsafe))
}",
);
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
index 8a8ff08cf..425432479 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
@@ -196,3 +196,34 @@ fn test(
"#,
);
}
+
+#[test]
+fn projection_type_correct_arguments_order() {
+ check_types_source_code(
+ r#"
+trait Foo<T> {
+ type Assoc<U>;
+}
+fn f<T: Foo<i32>>(a: T::Assoc<usize>) {
+ a;
+ //^ <T as Foo<i32>>::Assoc<usize>
+}
+"#,
+ );
+}
+
+#[test]
+fn generic_associated_type_binding_in_impl_trait() {
+ check_types_source_code(
+ r#"
+//- minicore: sized
+trait Foo<T> {
+ type Assoc<U>;
+}
+fn f(a: impl Foo<i8, Assoc<i16> = i32>) {
+ a;
+ //^ impl Foo<i8, Assoc<i16> = i32>
+}
+ "#,
+ );
+}
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 ac8edb841..5d76d185f 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
@@ -164,16 +164,16 @@ fn infer_associated_method_with_modules() {
check_infer(
r#"
mod a {
- struct A;
+ pub struct A;
impl A { pub fn thing() -> A { A {} }}
}
mod b {
- struct B;
+ pub struct B;
impl B { pub fn thing() -> u32 { 99 }}
- mod c {
- struct C;
+ pub mod c {
+ pub struct C;
impl C { pub fn thing() -> C { C {} }}
}
}
@@ -186,22 +186,22 @@ fn infer_associated_method_with_modules() {
}
"#,
expect![[r#"
- 55..63 '{ A {} }': A
- 57..61 'A {}': A
- 125..131 '{ 99 }': u32
- 127..129 '99': u32
- 201..209 '{ C {} }': C
- 203..207 'C {}': C
- 240..324 '{ ...g(); }': ()
- 250..251 'x': A
- 254..265 'a::A::thing': fn thing() -> A
- 254..267 'a::A::thing()': A
- 277..278 'y': u32
- 281..292 'b::B::thing': fn thing() -> u32
- 281..294 'b::B::thing()': u32
- 304..305 'z': C
- 308..319 'c::C::thing': fn thing() -> C
- 308..321 'c::C::thing()': C
+ 59..67 '{ A {} }': A
+ 61..65 'A {}': A
+ 133..139 '{ 99 }': u32
+ 135..137 '99': u32
+ 217..225 '{ C {} }': C
+ 219..223 'C {}': C
+ 256..340 '{ ...g(); }': ()
+ 266..267 'x': A
+ 270..281 'a::A::thing': fn thing() -> A
+ 270..283 'a::A::thing()': A
+ 293..294 'y': u32
+ 297..308 'b::B::thing': fn thing() -> u32
+ 297..310 'b::B::thing()': u32
+ 320..321 'z': C
+ 324..335 'c::C::thing': fn thing() -> C
+ 324..337 'c::C::thing()': C
"#]],
);
}
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 a155adcec..4e4639745 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
@@ -1707,3 +1707,19 @@ impl<T, const N: usize> Trait for [T; N] {
"#,
);
}
+
+#[test]
+fn unsize_array_with_inference_variable() {
+ check_types(
+ r#"
+//- minicore: try, slice
+use core::ops::ControlFlow;
+fn foo() -> ControlFlow<(), [usize; 1]> { loop {} }
+fn bar() -> ControlFlow<(), ()> {
+ let a = foo()?.len();
+ //^ usize
+ ControlFlow::Continue(())
+}
+"#,
+ );
+}
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 080e2ac1b..d7431443b 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
@@ -214,7 +214,7 @@ fn infer_paths() {
fn a() -> u32 { 1 }
mod b {
- fn c() -> u32 { 1 }
+ pub fn c() -> u32 { 1 }
}
fn test() {
@@ -225,13 +225,13 @@ fn test() {
expect![[r#"
14..19 '{ 1 }': u32
16..17 '1': u32
- 47..52 '{ 1 }': u32
- 49..50 '1': u32
- 66..90 '{ ...c(); }': ()
- 72..73 'a': fn a() -> u32
- 72..75 'a()': u32
- 81..85 'b::c': fn c() -> u32
- 81..87 'b::c()': u32
+ 51..56 '{ 1 }': u32
+ 53..54 '1': u32
+ 70..94 '{ ...c(); }': ()
+ 76..77 'a': fn a() -> u32
+ 76..79 'a()': u32
+ 85..89 'b::c': fn c() -> u32
+ 85..91 'b::c()': u32
"#]],
);
}
@@ -1856,7 +1856,7 @@ fn not_shadowing_module_by_primitive() {
check_types(
r#"
//- /str.rs
-fn foo() -> u32 {0}
+pub fn foo() -> u32 {0}
//- /main.rs
mod str;
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 555b6972f..3d7194b6f 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
@@ -1706,7 +1706,7 @@ fn where_clause_trait_in_scope_for_method_resolution() {
check_types(
r#"
mod foo {
- trait Trait {
+ pub trait Trait {
fn foo(&self) -> u32 { 0 }
}
}
@@ -1723,7 +1723,7 @@ fn super_trait_method_resolution() {
check_infer(
r#"
mod foo {
- trait SuperTrait {
+ pub trait SuperTrait {
fn foo(&self) -> u32 {}
}
}
@@ -1735,15 +1735,15 @@ fn test<T: Trait1, U: Trait2>(x: T, y: U) {
y.foo();
}"#,
expect![[r#"
- 49..53 'self': &Self
- 62..64 '{}': u32
- 181..182 'x': T
- 187..188 'y': U
- 193..222 '{ ...o(); }': ()
- 199..200 'x': T
- 199..206 'x.foo()': u32
- 212..213 'y': U
- 212..219 'y.foo()': u32
+ 53..57 'self': &Self
+ 66..68 '{}': u32
+ 185..186 'x': T
+ 191..192 'y': U
+ 197..226 '{ ...o(); }': ()
+ 203..204 'x': T
+ 203..210 'x.foo()': u32
+ 216..217 'y': U
+ 216..223 'y.foo()': u32
"#]],
);
}
@@ -1754,7 +1754,7 @@ fn super_trait_impl_trait_method_resolution() {
r#"
//- minicore: sized
mod foo {
- trait SuperTrait {
+ pub trait SuperTrait {
fn foo(&self) -> u32 {}
}
}
@@ -1764,12 +1764,12 @@ fn test(x: &impl Trait1) {
x.foo();
}"#,
expect![[r#"
- 49..53 'self': &Self
- 62..64 '{}': u32
- 115..116 'x': &impl Trait1
- 132..148 '{ ...o(); }': ()
- 138..139 'x': &impl Trait1
- 138..145 'x.foo()': u32
+ 53..57 'self': &Self
+ 66..68 '{}': u32
+ 119..120 'x': &impl Trait1
+ 136..152 '{ ...o(); }': ()
+ 142..143 'x': &impl Trait1
+ 142..149 'x.foo()': u32
"#]],
);
}
@@ -3963,3 +3963,124 @@ fn g(t: &(dyn T + Send)) {
"#,
);
}
+
+#[test]
+fn gats_in_path() {
+ check_types(
+ r#"
+//- minicore: deref
+use core::ops::Deref;
+trait PointerFamily {
+ type Pointer<T>: Deref<Target = T>;
+}
+
+fn f<P: PointerFamily>(p: P::Pointer<i32>) {
+ let a = *p;
+ //^ i32
+}
+fn g<P: PointerFamily>(p: <P as PointerFamily>::Pointer<i32>) {
+ let a = *p;
+ //^ i32
+}
+ "#,
+ );
+}
+
+#[test]
+fn gats_with_impl_trait() {
+ // FIXME: the last function (`fn i()`) is not valid Rust as of this writing because you cannot
+ // specify the same associated type multiple times even if their arguments are different (c.f.
+ // `fn h()`, which is valid). Reconsider how to treat these invalid types.
+ check_types(
+ r#"
+//- minicore: deref
+use core::ops::Deref;
+
+trait Trait {
+ type Assoc<T>: Deref<Target = T>;
+ fn get<U>(&self) -> Self::Assoc<U>;
+}
+
+fn f<T>(v: impl Trait) {
+ let a = v.get::<i32>().deref();
+ //^ &i32
+ let a = v.get::<T>().deref();
+ //^ &T
+}
+fn g<'a, T: 'a>(v: impl Trait<Assoc<T> = &'a T>) {
+ let a = v.get::<T>();
+ //^ &T
+ let a = v.get::<()>();
+ //^ Trait::Assoc<(), impl Trait<Assoc<T> = &T>>
+}
+fn h<'a>(v: impl Trait<Assoc<i32> = &'a i32> + Trait<Assoc<i64> = &'a i64>) {
+ let a = v.get::<i32>();
+ //^ &i32
+ let a = v.get::<i64>();
+ //^ &i64
+}
+fn i<'a>(v: impl Trait<Assoc<i32> = &'a i32, Assoc<i64> = &'a i64>) {
+ let a = v.get::<i32>();
+ //^ &i32
+ let a = v.get::<i64>();
+ //^ &i64
+}
+ "#,
+ );
+}
+
+#[test]
+fn gats_with_dyn() {
+ // This test is here to keep track of how we infer things despite traits with GATs being not
+ // object-safe currently.
+ // FIXME: reconsider how to treat these invalid types.
+ check_infer_with_mismatches(
+ r#"
+//- minicore: deref
+use core::ops::Deref;
+
+trait Trait {
+ type Assoc<T>: Deref<Target = T>;
+ fn get<U>(&self) -> Self::Assoc<U>;
+}
+
+fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) {
+ v.get::<i32>().deref();
+}
+ "#,
+ expect![[r#"
+ 90..94 'self': &Self
+ 127..128 'v': &(dyn Trait<Assoc<i32> = &i32>)
+ 164..195 '{ ...f(); }': ()
+ 170..171 'v': &(dyn Trait<Assoc<i32> = &i32>)
+ 170..184 'v.get::<i32>()': &i32
+ 170..192 'v.get:...eref()': &i32
+ "#]],
+ );
+}
+
+#[test]
+fn gats_in_associated_type_binding() {
+ check_types(
+ r#"
+trait Trait {
+ type Assoc<T>;
+ fn get<U>(&self) -> Self::Assoc<U>;
+}
+
+fn f<T>(t: T)
+where
+ T: Trait<Assoc<i32> = u32>,
+ T: Trait<Assoc<isize> = usize>,
+{
+ let a = t.get::<i32>();
+ //^ u32
+ let a = t.get::<isize>();
+ //^ usize
+ let a = t.get::<()>();
+ //^ Trait::Assoc<(), T>
+}
+
+ "#,
+ );
+}
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 547850b02..92711a24f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs
@@ -5,7 +5,7 @@ use itertools::Itertools;
use crate::{
chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
- CallableDefId, Interner,
+ CallableDefId, Interner, ProjectionTyExt,
};
use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId};
@@ -63,17 +63,31 @@ impl DebugContext<'_> {
ItemContainerId::TraitId(t) => t,
_ => panic!("associated type not in trait"),
};
- let trait_data = self.0.trait_data(trait_);
- let params = projection_ty.substitution.as_slice(Interner);
- write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?;
- if params.len() > 1 {
+ let trait_name = &self.0.trait_data(trait_).name;
+ 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)?;
+ if trait_params.len() > 1 {
+ write!(
+ fmt,
+ "<{}>",
+ trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
+ )?;
+ }
+ write!(fmt, ">::{}", type_alias_data.name)?;
+
+ let proj_params_count = projection_ty.substitution.len(Interner) - trait_params.len();
+ let proj_params = &projection_ty.substitution.as_slice(Interner)[..proj_params_count];
+ if !proj_params.is_empty() {
write!(
fmt,
"<{}>",
- &params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
+ proj_params.iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
)?;
}
- write!(fmt, ">::{}", type_alias_data.name)
+
+ Ok(())
}
pub(crate) fn debug_fn_def_id(