feat: Implement TAIT

This commit is contained in:
Shoyu Vanilla 2024-08-10 14:55:46 +09:00
parent bee4926ae7
commit 18b9458d64
14 changed files with 291 additions and 191 deletions

View File

@ -160,7 +160,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
fn const_data(&self, konst: ConstId) -> Arc<ConstData>; fn const_data(&self, konst: ConstId) -> Arc<ConstData>;
#[salsa::invoke(StaticData::static_data_query)] #[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)] #[salsa::invoke(Macro2Data::macro2_data_query)]
fn macro2_data(&self, makro: Macro2Id) -> Arc<Macro2Data>; fn macro2_data(&self, makro: Macro2Id) -> Arc<Macro2Data>;

View File

@ -275,7 +275,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
}; };
chalk_ir::Binders::new(binders, bound) chalk_ir::Binders::new(binders, bound)
} }
crate::ImplTraitId::AssociatedTypeImplTrait(alias, idx) => { crate::ImplTraitId::TypeAliasImplTrait(alias, idx) => {
let datas = self let datas = self
.db .db
.type_alias_impl_traits(alias) .type_alias_impl_traits(alias)

View File

@ -276,7 +276,7 @@ impl TyExt for Ty {
data.substitute(Interner, &subst).into_value_and_skipped_binders().0 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| { db.type_alias_impl_traits(alias).map(|it| {
let data = let data =
(*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); (*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) data.substitute(Interner, &opaque_ty.substitution)
}) })
} }
ImplTraitId::AssociatedTypeImplTrait(alias, idx) => { ImplTraitId::TypeAliasImplTrait(alias, idx) => {
db.type_alias_impl_traits(alias).map(|it| { db.type_alias_impl_traits(alias).map(|it| {
let data = let data =
(*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());

View File

@ -1151,11 +1151,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 // 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 = let datas =
db.type_alias_impl_traits(alias).expect("impl trait id without data"); db.type_alias_impl_traits(alias).expect("impl trait id without data");
let data = let data = (*datas).as_ref().map(|it| it.impl_traits[idx].bounds.clone());
(*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
let bounds = data.substitute(Interner, &parameters); let bounds = data.substitute(Interner, &parameters);
let krate = alias.krate(db.upcast()); let krate = alias.krate(db.upcast());
write_bounds_like_dyn_trait_with_prefix( write_bounds_like_dyn_trait_with_prefix(
@ -1338,7 +1337,7 @@ impl HirDisplay for Ty {
SizedByDefault::Sized { anchor: krate }, SizedByDefault::Sized { anchor: krate },
)?; )?;
} }
ImplTraitId::AssociatedTypeImplTrait(alias, idx) => { ImplTraitId::TypeAliasImplTrait(alias, idx) => {
let datas = let datas =
db.type_alias_impl_traits(alias).expect("impl trait id without data"); db.type_alias_impl_traits(alias).expect("impl trait id without data");
let data = let data =

View File

@ -36,15 +36,14 @@ use hir_def::{
body::Body, body::Body,
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
data::{ConstData, StaticData}, data::{ConstData, StaticData},
hir::LabelId, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, PatId},
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
layout::Integer, layout::Integer,
path::{ModPath, Path}, path::{ModPath, Path},
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
type_ref::{LifetimeRef, TypeRef}, type_ref::{LifetimeRef, TypeRef},
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, Lookup, TraitId, AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup,
TupleFieldId, TupleId, TypeAliasId, VariantId, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use indexmap::IndexSet; use indexmap::IndexSet;
@ -785,14 +784,19 @@ impl<'a> InferenceContext<'a> {
fn collect_const(&mut self, data: &ConstData) { fn collect_const(&mut self, data: &ConstData) {
let return_ty = self.make_ty(&data.type_ref); let return_ty = self.make_ty(&data.type_ref);
// Constants might be associated items that define ATPITs. // Constants might be defining usage sites of TAITs.
self.insert_atpit_coercion_table(iter::once(&return_ty)); self.make_tait_coercion_table(iter::once(&return_ty));
self.return_ty = return_ty; self.return_ty = return_ty;
} }
fn collect_static(&mut self, data: &StaticData) { 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) { 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_ty = self.normalize_associated_types_in(return_ty);
self.return_coercion = Some(CoerceMany::new(self.return_ty.clone())); self.return_coercion = Some(CoerceMany::new(self.return_ty.clone()));
// Functions might be associated items that define ATPITs. // Functions might be defining usage sites of TAITs.
// To define an ATPITs, that ATPIT must appear in the function's signatures. // To define an TAITs, that TAIT must appear in the function's signatures.
// So, it suffices to check for params and return types. // So, it suffices to check for params and return types.
params_and_ret_tys.push(self.return_ty.clone()); 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 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) => { ImplTraitId::ReturnTypeImplTrait(def, idx) => {
(self.db.return_type_impl_traits(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) (self.db.type_alias_impl_traits(def), idx)
} }
_ => unreachable!(), _ => unreachable!(),
@ -909,23 +913,25 @@ impl<'a> InferenceContext<'a> {
} }
/// The coercion of a non-inference var into an opaque type should fail, /// The coercion of a non-inference var into an opaque type should fail,
/// but not in the defining sites of the ATPITs. /// but not in the defining sites of the TAITs.
/// In such cases, we insert an proxy inference var for each ATPIT, /// In such cases, we insert an proxy inference var for each TAIT,
/// and coerce into it instead of ATPIT itself. /// and coerce into it instead of TAIT itself.
/// ///
/// The inference var stretagy is effective because; /// 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 /// - We are pushing `impl Trait` bounds into it
/// ///
/// This function inserts a map that maps the opaque type to that proxy inference var. /// 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>) { fn make_tait_coercion_table<'b>(&mut self, tait_candidates: impl Iterator<Item = &'b Ty>) {
struct OpaqueTyCollector<'a, 'b> { struct TypeAliasImplTraitCollector<'a, 'b> {
db: &'b dyn HirDatabase,
table: &'b mut InferenceTable<'a>, 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 = (); type BreakTy = ();
fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::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); let ty = self.table.resolve_ty_shallow(ty);
if let TyKind::OpaqueType(id, _) = ty.kind(Interner) { 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) ty.super_visit_with(self, outer_binder)
} }
} }
// Early return if this is not happening inside the impl block let mut collector = TypeAliasImplTraitCollector {
let impl_id = if let Some(impl_id) = self.resolver.impl_def() { db: self.db,
impl_id table: &mut self.table,
} else { assocs: FxHashMap::default(),
return; non_assocs: FxHashMap::default(),
}; };
for ty in tait_candidates {
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;
}
let mut collector =
OpaqueTyCollector { table: &mut self.table, opaque_tys: FxHashMap::default() };
for ty in tys {
ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST); ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST);
} }
let atpit_coercion_table: FxHashMap<_, _> = collector
.opaque_tys
.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())
{
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));
}
}
None // 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 tait_coercion_table: FxHashMap<_, _> = taits
.into_iter()
.filter_map(|(id, ty)| {
if let ImplTraitId::TypeAliasImplTrait(alias_id, _) =
self.db.lookup_intern_impl_trait_id(id.into())
{
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
}
}) })
.collect(); .collect();
if !atpit_coercion_table.is_empty() { if !tait_coercion_table.is_empty() {
self.table.atpit_coercion_table = Some(atpit_coercion_table); self.table.tait_coercion_table = Some(tait_coercion_table);
} }
} }

View File

@ -276,16 +276,16 @@ impl InferenceTable<'_> {
return success(simple(Adjust::NeverToAny)(to_ty.clone()), to_ty.clone(), vec![]); 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 mut to_ty = to_ty;
let _to; 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 let TyKind::OpaqueType(opaque_ty_id, _) = to_ty.kind(Interner) {
if !matches!( if !matches!(
from_ty.kind(Interner), from_ty.kind(Interner),
TyKind::InferenceVar(..) | TyKind::OpaqueType(..) 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.clone();
to_ty = &_to; to_ty = &_to;
} }

View File

@ -224,7 +224,7 @@ type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
pub(crate) struct InferenceTable<'a> { pub(crate) struct InferenceTable<'a> {
pub(crate) db: &'a dyn HirDatabase, pub(crate) db: &'a dyn HirDatabase,
pub(crate) trait_env: Arc<TraitEnvironment>, 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, var_unification_table: ChalkInferenceTable,
type_variable_table: SmallVec<[TypeVariableFlags; 16]>, type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>, pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
@ -244,7 +244,7 @@ impl<'a> InferenceTable<'a> {
InferenceTable { InferenceTable {
db, db,
trait_env, trait_env,
atpit_coercion_table: None, tait_coercion_table: None,
var_unification_table: ChalkInferenceTable::new(), var_unification_table: ChalkInferenceTable::new(),
type_variable_table: SmallVec::new(), type_variable_table: SmallVec::new(),
pending_obligations: Vec::new(), pending_obligations: Vec::new(),

View File

@ -391,7 +391,7 @@ pub fn layout_of_ty_query(
let infer = db.infer(func.into()); let infer = db.infer(func.into());
return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env); return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env);
} }
crate::ImplTraitId::AssociatedTypeImplTrait(..) => { crate::ImplTraitId::TypeAliasImplTrait(..) => {
return Err(LayoutError::NotImplemented); return Err(LayoutError::NotImplemented);
} }
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {

View File

@ -595,7 +595,7 @@ impl TypeFoldable<Interner> for CallableSig {
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum ImplTraitId { pub enum ImplTraitId {
ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx), ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx),
AssociatedTypeImplTrait(hir_def::TypeAliasId, ImplTraitIdx), TypeAliasImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
} }
impl InternValueTrivial for ImplTraitId {} impl InternValueTrivial for ImplTraitId {}

View File

@ -341,7 +341,7 @@ impl<'a> TyLoweringContext<'a> {
let impl_trait_id = origin.either( let impl_trait_id = origin.either(
|f| ImplTraitId::ReturnTypeImplTrait(f, idx), |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 opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
let generics = let generics =
@ -2131,7 +2131,6 @@ pub(crate) fn type_alias_impl_traits(
if let Some(type_ref) = &data.type_ref { if let Some(type_ref) = &data.type_ref {
let _ty = ctx.lower_ty(type_ref); let _ty = ctx.lower_ty(type_ref);
} }
let generics = generics(db.upcast(), def.into());
let type_alias_impl_traits = ImplTraits { let type_alias_impl_traits = ImplTraits {
impl_traits: match ctx.impl_trait_mode { impl_traits: match ctx.impl_trait_mode {
ImplTraitLoweringState::Opaque(x) => x.into_inner(), 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() { if type_alias_impl_traits.impl_traits.is_empty() {
None None
} else { } else {
let generics = generics(db.upcast(), def.into());
Some(Arc::new(make_binders(db, &generics, type_alias_impl_traits))) Some(Arc::new(make_binders(db, &generics, type_alias_impl_traits)))
} }
} }

View File

@ -82,8 +82,8 @@ impl FallibleTypeFolder<Interner> for Filler<'_> {
}; };
filler.try_fold_ty(infer.type_of_rpit[idx].clone(), outer_binder) filler.try_fold_ty(infer.type_of_rpit[idx].clone(), outer_binder)
} }
crate::ImplTraitId::AssociatedTypeImplTrait(..) => { crate::ImplTraitId::TypeAliasImplTrait(..) => {
not_supported!("associated type impl trait"); not_supported!("type alias impl trait");
} }
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
not_supported!("async block impl trait"); not_supported!("async block impl trait");

View File

@ -9,6 +9,7 @@ mod patterns;
mod regression; mod regression;
mod simple; mod simple;
mod traits; mod traits;
mod type_alias_impl_traits;
use std::env; use std::env;

View File

@ -4691,119 +4691,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] #[test]
fn dyn_trait_with_lifetime_in_rpit() { fn dyn_trait_with_lifetime_in_rpit() {
check_types( check_types(

View File

@ -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
"#]],
)
}