Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #17845 - ShoyuVanilla:tait, r=Veykril
feat: Implement TAIT and fix ATPIT a bit Closes #16296 (Commented on the issue) In #16852, I implemented ATPIT, but as I didn't discern ATPIT and other non-assoc TAIT, I guess that it has been working for some TAITs. As the definining usage of TAIT requires it should be appear in the Def body's type(const blocks' type annotations or functions' signatures), this can be done in simlilar way with ATPIT And this PR also corrects some defining-usage resolution for ATPIT
bors 2024-08-12
parent 0daeb5c · parent c530e21 · commit 6d9af33
-rw-r--r--crates/hir-def/src/db.rs2
-rw-r--r--crates/hir-ty/src/chalk_db.rs2
-rw-r--r--crates/hir-ty/src/chalk_ext.rs4
-rw-r--r--crates/hir-ty/src/display.rs7
-rw-r--r--crates/hir-ty/src/infer.rs164
-rw-r--r--crates/hir-ty/src/infer/coerce.rs6
-rw-r--r--crates/hir-ty/src/infer/unify.rs4
-rw-r--r--crates/hir-ty/src/layout.rs2
-rw-r--r--crates/hir-ty/src/lib.rs2
-rw-r--r--crates/hir-ty/src/lower.rs4
-rw-r--r--crates/hir-ty/src/mir/monomorphization.rs4
-rw-r--r--crates/hir-ty/src/tests.rs1
-rw-r--r--crates/hir-ty/src/tests/traits.rs113
-rw-r--r--crates/hir-ty/src/tests/type_alias_impl_traits.rs161
14 files changed, 288 insertions, 188 deletions
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 56feb0163e..9ba99788fb 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -160,7 +160,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
fn const_data(&self, konst: ConstId) -> Arc<ConstData>;
#[salsa::invoke(StaticData::static_data_query)]
- fn static_data(&self, konst: StaticId) -> Arc<StaticData>;
+ fn static_data(&self, statik: StaticId) -> Arc<StaticData>;
#[salsa::invoke(Macro2Data::macro2_data_query)]
fn macro2_data(&self, makro: Macro2Id) -> Arc<Macro2Data>;
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index d506e00ca1..a151ee01e6 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -275,7 +275,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
};
chalk_ir::Binders::new(binders, bound)
}
- crate::ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
+ crate::ImplTraitId::TypeAliasImplTrait(alias, idx) => {
let datas = self
.db
.type_alias_impl_traits(alias)
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index 5765262b08..302558162a 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -276,7 +276,7 @@ impl TyExt for Ty {
data.substitute(Interner, &subst).into_value_and_skipped_binders().0
})
}
- ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
+ ImplTraitId::TypeAliasImplTrait(alias, idx) => {
db.type_alias_impl_traits(alias).map(|it| {
let data =
(*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
@@ -295,7 +295,7 @@ impl TyExt for Ty {
data.substitute(Interner, &opaque_ty.substitution)
})
}
- ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
+ ImplTraitId::TypeAliasImplTrait(alias, idx) => {
db.type_alias_impl_traits(alias).map(|it| {
let data =
(*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 64825ea215..7c481958d1 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -1152,11 +1152,10 @@ impl HirDisplay for Ty {
)?;
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
}
- ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
+ ImplTraitId::TypeAliasImplTrait(alias, idx) => {
let datas =
db.type_alias_impl_traits(alias).expect("impl trait id without data");
- let data =
- (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
+ let data = (*datas).as_ref().map(|it| it.impl_traits[idx].bounds.clone());
let bounds = data.substitute(Interner, &parameters);
let krate = alias.krate(db.upcast());
write_bounds_like_dyn_trait_with_prefix(
@@ -1339,7 +1338,7 @@ impl HirDisplay for Ty {
SizedByDefault::Sized { anchor: krate },
)?;
}
- ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
+ ImplTraitId::TypeAliasImplTrait(alias, idx) => {
let datas =
db.type_alias_impl_traits(alias).expect("impl trait id without data");
let data =
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 804bc53905..45d423d03c 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -36,15 +36,14 @@ use hir_def::{
body::Body,
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
data::{ConstData, StaticData},
- hir::LabelId,
- hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, PatId},
+ hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
lang_item::{LangItem, LangItemTarget},
layout::Integer,
path::{ModPath, Path},
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
type_ref::{LifetimeRef, TypeRef},
- AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, Lookup, TraitId,
- TupleFieldId, TupleId, TypeAliasId, VariantId,
+ AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup,
+ TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
};
use hir_expand::name::Name;
use indexmap::IndexSet;
@@ -785,14 +784,19 @@ impl<'a> InferenceContext<'a> {
fn collect_const(&mut self, data: &ConstData) {
let return_ty = self.make_ty(&data.type_ref);
- // Constants might be associated items that define ATPITs.
- self.insert_atpit_coercion_table(iter::once(&return_ty));
+ // Constants might be defining usage sites of TAITs.
+ self.make_tait_coercion_table(iter::once(&return_ty));
self.return_ty = return_ty;
}
fn collect_static(&mut self, data: &StaticData) {
- self.return_ty = self.make_ty(&data.type_ref);
+ let return_ty = self.make_ty(&data.type_ref);
+
+ // Statics might be defining usage sites of TAITs.
+ self.make_tait_coercion_table(iter::once(&return_ty));
+
+ self.return_ty = return_ty;
}
fn collect_fn(&mut self, func: FunctionId) {
@@ -857,11 +861,11 @@ impl<'a> InferenceContext<'a> {
self.return_ty = self.normalize_associated_types_in(return_ty);
self.return_coercion = Some(CoerceMany::new(self.return_ty.clone()));
- // Functions might be associated items that define ATPITs.
- // To define an ATPITs, that ATPIT must appear in the function's signatures.
+ // Functions might be defining usage sites of TAITs.
+ // To define an TAITs, that TAIT must appear in the function's signatures.
// So, it suffices to check for params and return types.
params_and_ret_tys.push(self.return_ty.clone());
- self.insert_atpit_coercion_table(params_and_ret_tys.iter());
+ self.make_tait_coercion_table(params_and_ret_tys.iter());
}
fn insert_inference_vars_for_impl_trait<T>(&mut self, t: T, placeholders: Substitution) -> T
@@ -880,7 +884,7 @@ impl<'a> InferenceContext<'a> {
ImplTraitId::ReturnTypeImplTrait(def, idx) => {
(self.db.return_type_impl_traits(def), idx)
}
- ImplTraitId::AssociatedTypeImplTrait(def, idx) => {
+ ImplTraitId::TypeAliasImplTrait(def, idx) => {
(self.db.type_alias_impl_traits(def), idx)
}
_ => unreachable!(),
@@ -909,23 +913,25 @@ impl<'a> InferenceContext<'a> {
}
/// The coercion of a non-inference var into an opaque type should fail,
- /// but not in the defining sites of the ATPITs.
- /// In such cases, we insert an proxy inference var for each ATPIT,
- /// and coerce into it instead of ATPIT itself.
+ /// but not in the defining sites of the TAITs.
+ /// In such cases, we insert an proxy inference var for each TAIT,
+ /// and coerce into it instead of TAIT itself.
///
/// The inference var stretagy is effective because;
///
- /// - It can still unify types that coerced into ATPIT
+ /// - It can still unify types that coerced into TAITs
/// - We are pushing `impl Trait` bounds into it
///
/// This function inserts a map that maps the opaque type to that proxy inference var.
- fn insert_atpit_coercion_table<'b>(&mut self, tys: impl Iterator<Item = &'b Ty>) {
- struct OpaqueTyCollector<'a, 'b> {
+ fn make_tait_coercion_table<'b>(&mut self, tait_candidates: impl Iterator<Item = &'b Ty>) {
+ struct TypeAliasImplTraitCollector<'a, 'b> {
+ db: &'b dyn HirDatabase,
table: &'b mut InferenceTable<'a>,
- opaque_tys: FxHashMap<OpaqueTyId, Ty>,
+ assocs: FxHashMap<OpaqueTyId, (ImplId, Ty)>,
+ non_assocs: FxHashMap<OpaqueTyId, Ty>,
}
- impl<'a, 'b> TypeVisitor<Interner> for OpaqueTyCollector<'a, 'b> {
+ impl<'a, 'b> TypeVisitor<Interner> for TypeAliasImplTraitCollector<'a, 'b> {
type BreakTy = ();
fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
@@ -944,59 +950,105 @@ impl<'a> InferenceContext<'a> {
let ty = self.table.resolve_ty_shallow(ty);
if let TyKind::OpaqueType(id, _) = ty.kind(Interner) {
- self.opaque_tys.insert(*id, ty.clone());
+ if let ImplTraitId::TypeAliasImplTrait(alias_id, _) =
+ self.db.lookup_intern_impl_trait_id((*id).into())
+ {
+ let loc = self.db.lookup_intern_type_alias(alias_id);
+ match loc.container {
+ ItemContainerId::ImplId(impl_id) => {
+ self.assocs.insert(*id, (impl_id, ty.clone()));
+ }
+ ItemContainerId::ModuleId(..) | ItemContainerId::ExternBlockId(..) => {
+ self.non_assocs.insert(*id, ty.clone());
+ }
+ _ => {}
+ }
+ }
}
ty.super_visit_with(self, outer_binder)
}
}
- // Early return if this is not happening inside the impl block
- let impl_id = if let Some(impl_id) = self.resolver.impl_def() {
- impl_id
- } else {
- return;
+ let mut collector = TypeAliasImplTraitCollector {
+ db: self.db,
+ table: &mut self.table,
+ assocs: FxHashMap::default(),
+ non_assocs: FxHashMap::default(),
};
-
- let assoc_tys: FxHashSet<_> = self
- .db
- .impl_data(impl_id)
- .items
- .iter()
- .filter_map(|item| match item {
- AssocItemId::TypeAliasId(alias) => Some(*alias),
- _ => None,
- })
- .collect();
- if assoc_tys.is_empty() {
- return;
+ for ty in tait_candidates {
+ ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST);
}
- let mut collector =
- OpaqueTyCollector { table: &mut self.table, opaque_tys: FxHashMap::default() };
- for ty in tys {
- ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST);
+ // Non-assoc TAITs can be define-used everywhere as long as they are
+ // in function signatures or const types, etc
+ let mut taits = collector.non_assocs;
+
+ // assoc TAITs(ATPITs) can be only define-used inside their impl block.
+ // They cannot be define-used in inner items like in the following;
+ //
+ // ```
+ // impl Trait for Struct {
+ // type Assoc = impl Default;
+ //
+ // fn assoc_fn() -> Self::Assoc {
+ // let foo: Self::Assoc = true; // Allowed here
+ //
+ // fn inner() -> Self::Assoc {
+ // false // Not allowed here
+ // }
+ //
+ // foo
+ // }
+ // }
+ // ```
+ let impl_id = match self.owner {
+ DefWithBodyId::FunctionId(it) => {
+ let loc = self.db.lookup_intern_function(it);
+ if let ItemContainerId::ImplId(impl_id) = loc.container {
+ Some(impl_id)
+ } else {
+ None
+ }
+ }
+ DefWithBodyId::ConstId(it) => {
+ let loc = self.db.lookup_intern_const(it);
+ if let ItemContainerId::ImplId(impl_id) = loc.container {
+ Some(impl_id)
+ } else {
+ None
+ }
+ }
+ _ => None,
+ };
+
+ if let Some(impl_id) = impl_id {
+ taits.extend(collector.assocs.into_iter().filter_map(|(id, (impl_, ty))| {
+ if impl_ == impl_id {
+ Some((id, ty))
+ } else {
+ None
+ }
+ }));
}
- let atpit_coercion_table: FxHashMap<_, _> = collector
- .opaque_tys
+
+ let tait_coercion_table: FxHashMap<_, _> = taits
.into_iter()
- .filter_map(|(opaque_ty_id, ty)| {
- if let ImplTraitId::AssociatedTypeImplTrait(alias_id, _) =
- self.db.lookup_intern_impl_trait_id(opaque_ty_id.into())
+ .filter_map(|(id, ty)| {
+ if let ImplTraitId::TypeAliasImplTrait(alias_id, _) =
+ self.db.lookup_intern_impl_trait_id(id.into())
{
- if assoc_tys.contains(&alias_id) {
- let alias_placeholders = TyBuilder::placeholder_subst(self.db, alias_id);
- let ty = self.insert_inference_vars_for_impl_trait(ty, alias_placeholders);
- return Some((opaque_ty_id, ty));
- }
+ let subst = TyBuilder::placeholder_subst(self.db, alias_id);
+ let ty = self.insert_inference_vars_for_impl_trait(ty, subst);
+ Some((id, ty))
+ } else {
+ None
}
-
- None
})
.collect();
- if !atpit_coercion_table.is_empty() {
- self.table.atpit_coercion_table = Some(atpit_coercion_table);
+ if !tait_coercion_table.is_empty() {
+ self.table.tait_coercion_table = Some(tait_coercion_table);
}
}
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index 72928851f1..6f85a4a424 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -276,16 +276,16 @@ impl InferenceTable<'_> {
return success(simple(Adjust::NeverToAny)(to_ty.clone()), to_ty.clone(), vec![]);
}
- // If we are coercing into an ATPIT, coerce into its proxy inference var, instead.
+ // If we are coercing into a TAIT, coerce into its proxy inference var, instead.
let mut to_ty = to_ty;
let _to;
- if let Some(atpit_table) = &self.atpit_coercion_table {
+ if let Some(tait_table) = &self.tait_coercion_table {
if let TyKind::OpaqueType(opaque_ty_id, _) = to_ty.kind(Interner) {
if !matches!(
from_ty.kind(Interner),
TyKind::InferenceVar(..) | TyKind::OpaqueType(..)
) {
- if let Some(ty) = atpit_table.get(opaque_ty_id) {
+ if let Some(ty) = tait_table.get(opaque_ty_id) {
_to = ty.clone();
to_ty = &_to;
}
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 7ee63af1c2..3e3578b9f9 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -224,7 +224,7 @@ type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
pub(crate) struct InferenceTable<'a> {
pub(crate) db: &'a dyn HirDatabase,
pub(crate) trait_env: Arc<TraitEnvironment>,
- pub(crate) atpit_coercion_table: Option<FxHashMap<OpaqueTyId, Ty>>,
+ pub(crate) tait_coercion_table: Option<FxHashMap<OpaqueTyId, Ty>>,
var_unification_table: ChalkInferenceTable,
type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
@@ -244,7 +244,7 @@ impl<'a> InferenceTable<'a> {
InferenceTable {
db,
trait_env,
- atpit_coercion_table: None,
+ tait_coercion_table: None,
var_unification_table: ChalkInferenceTable::new(),
type_variable_table: SmallVec::new(),
pending_obligations: Vec::new(),
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs
index 034b9c773c..47cc2a2f1e 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -391,7 +391,7 @@ pub fn layout_of_ty_query(
let infer = db.infer(func.into());
return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env);
}
- crate::ImplTraitId::AssociatedTypeImplTrait(..) => {
+ crate::ImplTraitId::TypeAliasImplTrait(..) => {
return Err(LayoutError::NotImplemented);
}
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 2f93ce3181..4c9e0a1e11 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -595,7 +595,7 @@ impl TypeFoldable<Interner> for CallableSig {
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum ImplTraitId {
ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx),
- AssociatedTypeImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
+ TypeAliasImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
}
impl InternValueTrivial for ImplTraitId {}
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 444628ff52..f0fcdff7e3 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -341,7 +341,7 @@ impl<'a> TyLoweringContext<'a> {
let impl_trait_id = origin.either(
|f| ImplTraitId::ReturnTypeImplTrait(f, idx),
- |a| ImplTraitId::AssociatedTypeImplTrait(a, idx),
+ |a| ImplTraitId::TypeAliasImplTrait(a, idx),
);
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
let generics =
@@ -2131,7 +2131,6 @@ pub(crate) fn type_alias_impl_traits(
if let Some(type_ref) = &data.type_ref {
let _ty = ctx.lower_ty(type_ref);
}
- let generics = generics(db.upcast(), def.into());
let type_alias_impl_traits = ImplTraits {
impl_traits: match ctx.impl_trait_mode {
ImplTraitLoweringState::Opaque(x) => x.into_inner(),
@@ -2141,6 +2140,7 @@ pub(crate) fn type_alias_impl_traits(
if type_alias_impl_traits.impl_traits.is_empty() {
None
} else {
+ let generics = generics(db.upcast(), def.into());
Some(Arc::new(make_binders(db, &generics, type_alias_impl_traits)))
}
}
diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs
index 172dea02e6..8f6582b7f8 100644
--- a/crates/hir-ty/src/mir/monomorphization.rs
+++ b/crates/hir-ty/src/mir/monomorphization.rs
@@ -82,8 +82,8 @@ impl FallibleTypeFolder<Interner> for Filler<'_> {
};
filler.try_fold_ty(infer.type_of_rpit[idx].clone(), outer_binder)
}
- crate::ImplTraitId::AssociatedTypeImplTrait(..) => {
- not_supported!("associated type impl trait");
+ crate::ImplTraitId::TypeAliasImplTrait(..) => {
+ not_supported!("type alias impl trait");
}
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
not_supported!("async block impl trait");
diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs
index 19619008e3..0fcd789f76 100644
--- a/crates/hir-ty/src/tests.rs
+++ b/crates/hir-ty/src/tests.rs
@@ -9,6 +9,7 @@ mod patterns;
mod regression;
mod simple;
mod traits;
+mod type_alias_impl_traits;
use std::env;
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index fb07e718d1..a98cff2a08 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -4692,119 +4692,6 @@ fn f<T: Send, U>() {
}
#[test]
-fn associated_type_impl_trait() {
- check_types(
- r#"
-trait Foo {}
-struct S1;
-impl Foo for S1 {}
-
-trait Bar {
- type Item;
- fn bar(&self) -> Self::Item;
-}
-struct S2;
-impl Bar for S2 {
- type Item = impl Foo;
- fn bar(&self) -> Self::Item {
- S1
- }
-}
-
-fn test() {
- let x = S2.bar();
- //^ impl Foo + ?Sized
-}
- "#,
- );
-}
-
-#[test]
-fn associated_type_impl_traits_complex() {
- check_types(
- r#"
-struct Unary<T>(T);
-struct Binary<T, U>(T, U);
-
-trait Foo {}
-struct S1;
-impl Foo for S1 {}
-
-trait Bar {
- type Item;
- fn bar(&self) -> Unary<Self::Item>;
-}
-struct S2;
-impl Bar for S2 {
- type Item = Unary<impl Foo>;
- fn bar(&self) -> Unary<<Self as Bar>::Item> {
- Unary(Unary(S1))
- }
-}
-
-trait Baz {
- type Target1;
- type Target2;
- fn baz(&self) -> Binary<Self::Target1, Self::Target2>;
-}
-struct S3;
-impl Baz for S3 {
- type Target1 = impl Foo;
- type Target2 = Unary<impl Bar>;
- fn baz(&self) -> Binary<Self::Target1, Self::Target2> {
- Binary(S1, Unary(S2))
- }
-}
-
-fn test() {
- let x = S3.baz();
- //^ Binary<impl Foo + ?Sized, Unary<impl Bar + ?Sized>>
- let y = x.1.0.bar();
- //^ Unary<Bar::Item<impl Bar + ?Sized>>
-}
- "#,
- );
-}
-
-#[test]
-fn associated_type_with_impl_trait_in_tuple() {
- check_no_mismatches(
- r#"
-pub trait Iterator {
- type Item;
-}
-
-pub trait Value {}
-
-fn bar<I: Iterator<Item = (usize, impl Value)>>() {}
-
-fn foo() {
- bar();
-}
-"#,
- );
-}
-
-#[test]
-fn associated_type_with_impl_trait_in_nested_tuple() {
- check_no_mismatches(
- r#"
-pub trait Iterator {
- type Item;
-}
-
-pub trait Value {}
-
-fn bar<I: Iterator<Item = ((impl Value, usize), u32)>>() {}
-
-fn foo() {
- bar();
-}
-"#,
- );
-}
-
-#[test]
fn dyn_trait_with_lifetime_in_rpit() {
check_types(
r#"
diff --git a/crates/hir-ty/src/tests/type_alias_impl_traits.rs b/crates/hir-ty/src/tests/type_alias_impl_traits.rs
new file mode 100644
index 0000000000..e2b7bf379c
--- /dev/null
+++ b/crates/hir-ty/src/tests/type_alias_impl_traits.rs
@@ -0,0 +1,161 @@
+use expect_test::expect;
+
+use super::{check_infer_with_mismatches, check_no_mismatches, check_types};
+
+#[test]
+fn associated_type_impl_trait() {
+ check_types(
+ r#"
+trait Foo {}
+struct S1;
+impl Foo for S1 {}
+
+trait Bar {
+ type Item;
+ fn bar(&self) -> Self::Item;
+}
+struct S2;
+impl Bar for S2 {
+ type Item = impl Foo;
+ fn bar(&self) -> Self::Item {
+ S1
+ }
+}
+
+fn test() {
+ let x = S2.bar();
+ //^ impl Foo + ?Sized
+}
+ "#,
+ );
+}
+
+#[test]
+fn associated_type_impl_traits_complex() {
+ check_types(
+ r#"
+struct Unary<T>(T);
+struct Binary<T, U>(T, U);
+
+trait Foo {}
+struct S1;
+impl Foo for S1 {}
+
+trait Bar {
+ type Item;
+ fn bar(&self) -> Unary<Self::Item>;
+}
+struct S2;
+impl Bar for S2 {
+ type Item = Unary<impl Foo>;
+ fn bar(&self) -> Unary<<Self as Bar>::Item> {
+ Unary(Unary(S1))
+ }
+}
+
+trait Baz {
+ type Target1;
+ type Target2;
+ fn baz(&self) -> Binary<Self::Target1, Self::Target2>;
+}
+struct S3;
+impl Baz for S3 {
+ type Target1 = impl Foo;
+ type Target2 = Unary<impl Bar>;
+ fn baz(&self) -> Binary<Self::Target1, Self::Target2> {
+ Binary(S1, Unary(S2))
+ }
+}
+
+fn test() {
+ let x = S3.baz();
+ //^ Binary<impl Foo + ?Sized, Unary<impl Bar + ?Sized>>
+ let y = x.1.0.bar();
+ //^ Unary<Bar::Item<impl Bar + ?Sized>>
+}
+ "#,
+ );
+}
+
+#[test]
+fn associated_type_with_impl_trait_in_tuple() {
+ check_no_mismatches(
+ r#"
+pub trait Iterator {
+ type Item;
+}
+
+pub trait Value {}
+
+fn bar<I: Iterator<Item = (usize, impl Value)>>() {}
+
+fn foo() {
+ bar();
+}
+"#,
+ );
+}
+
+#[test]
+fn associated_type_with_impl_trait_in_nested_tuple() {
+ check_no_mismatches(
+ r#"
+pub trait Iterator {
+ type Item;
+}
+
+pub trait Value {}
+
+fn bar<I: Iterator<Item = ((impl Value, usize), u32)>>() {}
+
+fn foo() {
+ bar();
+}
+"#,
+ );
+}
+
+#[test]
+fn type_alias_impl_trait_simple() {
+ check_no_mismatches(
+ r#"
+trait Trait {}
+
+struct Struct;
+
+impl Trait for Struct {}
+
+type AliasTy = impl Trait;
+
+static ALIAS: AliasTy = {
+ let res: AliasTy = Struct;
+ res
+};
+"#,
+ );
+
+ check_infer_with_mismatches(
+ r#"
+trait Trait {}
+
+struct Struct;
+
+impl Trait for Struct {}
+
+type AliasTy = impl Trait;
+
+static ALIAS: i32 = {
+ // TATIs cannot be define-used if not in signature or type annotations
+ let _a: AliasTy = Struct;
+ 5
+};
+"#,
+ expect![[r#"
+ 106..220 '{ ... 5 }': i32
+ 191..193 '_a': impl Trait + ?Sized
+ 205..211 'Struct': Struct
+ 217..218 '5': i32
+ 205..211: expected impl Trait + ?Sized, got Struct
+ "#]],
+ )
+}