feat: Implement TAIT
This commit is contained in:
parent
bee4926ae7
commit
18b9458d64
@ -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>;
|
||||||
|
@ -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)
|
||||||
|
@ -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());
|
||||||
|
@ -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, ¶meters);
|
let bounds = data.substitute(Interner, ¶meters);
|
||||||
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 =
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
|
@ -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(_, _) => {
|
||||||
|
@ -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 {}
|
||||||
|
@ -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)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
@ -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…
x
Reference in New Issue
Block a user