mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
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
This commit is contained in:
commit
3ef56c2bb8
@ -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>;
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
|
@ -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, ¶meters);
|
||||
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 =
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
let mut collector =
|
||||
OpaqueTyCollector { table: &mut self.table, opaque_tys: FxHashMap::default() };
|
||||
for ty in tys {
|
||||
for ty in tait_candidates {
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(),
|
||||
|
@ -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(_, _) => {
|
||||
|
@ -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 {}
|
||||
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -9,6 +9,7 @@ mod patterns;
|
||||
mod regression;
|
||||
mod simple;
|
||||
mod traits;
|
||||
mod type_alias_impl_traits;
|
||||
|
||||
use std::env;
|
||||
|
||||
|
@ -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]
|
||||
fn dyn_trait_with_lifetime_in_rpit() {
|
||||
check_types(
|
||||
|
@ -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
|
||||
"#]],
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user