mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 05:53:45 +00:00
feat: Implement ATPIT
This commit is contained in:
parent
f9a4d05195
commit
d2aba91a0c
13 changed files with 365 additions and 55 deletions
|
@ -272,6 +272,19 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
||||||
};
|
};
|
||||||
chalk_ir::Binders::new(binders, bound)
|
chalk_ir::Binders::new(binders, bound)
|
||||||
}
|
}
|
||||||
|
crate::ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
|
||||||
|
let datas = self
|
||||||
|
.db
|
||||||
|
.type_alias_impl_traits(alias)
|
||||||
|
.expect("impl trait id without impl traits");
|
||||||
|
let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
|
||||||
|
let data = &datas.impl_traits[idx];
|
||||||
|
let bound = OpaqueTyDatumBound {
|
||||||
|
bounds: make_single_type_binders(data.bounds.skip_binders().to_vec()),
|
||||||
|
where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
|
||||||
|
};
|
||||||
|
chalk_ir::Binders::new(binders, bound)
|
||||||
|
}
|
||||||
crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
||||||
if let Some((future_trait, future_output)) = self
|
if let Some((future_trait, future_output)) = self
|
||||||
.db
|
.db
|
||||||
|
|
|
@ -268,6 +268,13 @@ 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) => {
|
||||||
|
db.type_alias_impl_traits(alias).map(|it| {
|
||||||
|
let data =
|
||||||
|
(*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
|
||||||
|
data.substitute(Interner, &subst).into_value_and_skipped_binders().0
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
|
TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
|
||||||
|
@ -280,6 +287,13 @@ impl TyExt for Ty {
|
||||||
data.substitute(Interner, &opaque_ty.substitution)
|
data.substitute(Interner, &opaque_ty.substitution)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ImplTraitId::AssociatedTypeImplTrait(alias, idx) => {
|
||||||
|
db.type_alias_impl_traits(alias).map(|it| {
|
||||||
|
let data =
|
||||||
|
(*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
|
||||||
|
data.substitute(Interner, &opaque_ty.substitution)
|
||||||
|
})
|
||||||
|
}
|
||||||
// It always has an parameter for Future::Output type.
|
// It always has an parameter for Future::Output type.
|
||||||
ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
|
ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@ use base_db::{
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, ConstParamId,
|
db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, ConstParamId,
|
||||||
DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId,
|
DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId,
|
||||||
LifetimeParamId, LocalFieldId, StaticId, TypeOrConstParamId, VariantId,
|
LifetimeParamId, LocalFieldId, StaticId, TypeAliasId, TypeOrConstParamId, VariantId,
|
||||||
};
|
};
|
||||||
use la_arena::ArenaMap;
|
use la_arena::ArenaMap;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -23,9 +23,9 @@ use crate::{
|
||||||
layout::{Layout, LayoutError},
|
layout::{Layout, LayoutError},
|
||||||
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
|
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
|
||||||
mir::{BorrowckResult, MirBody, MirLowerError},
|
mir::{BorrowckResult, MirBody, MirLowerError},
|
||||||
Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, InferenceResult,
|
Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, ImplTraits,
|
||||||
Interner, PolyFnSig, QuantifiedWhereClause, ReturnTypeImplTraits, Substitution,
|
InferenceResult, Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment,
|
||||||
TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId,
|
TraitRef, Ty, TyDefId, ValueTyDefId,
|
||||||
};
|
};
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
|
|
||||||
|
@ -132,10 +132,10 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
||||||
fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
|
fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
|
||||||
|
|
||||||
#[salsa::invoke(crate::lower::return_type_impl_traits)]
|
#[salsa::invoke(crate::lower::return_type_impl_traits)]
|
||||||
fn return_type_impl_traits(
|
fn return_type_impl_traits(&self, def: FunctionId) -> Option<Arc<Binders<ImplTraits>>>;
|
||||||
&self,
|
|
||||||
def: FunctionId,
|
#[salsa::invoke(crate::lower::type_alias_impl_traits)]
|
||||||
) -> Option<Arc<Binders<ReturnTypeImplTraits>>>;
|
fn type_alias_impl_traits(&self, def: TypeAliasId) -> Option<Arc<Binders<ImplTraits>>>;
|
||||||
|
|
||||||
#[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
|
#[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
|
||||||
#[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
|
#[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
|
||||||
|
|
|
@ -1063,6 +1063,20 @@ 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) => {
|
||||||
|
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 bounds = data.substitute(Interner, ¶meters);
|
||||||
|
let krate = alias.krate(db.upcast());
|
||||||
|
write_bounds_like_dyn_trait_with_prefix(
|
||||||
|
f,
|
||||||
|
"impl",
|
||||||
|
bounds.skip_binders(),
|
||||||
|
SizedByDefault::Sized { anchor: krate },
|
||||||
|
)?;
|
||||||
|
}
|
||||||
ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => {
|
ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => {
|
||||||
let future_trait = db
|
let future_trait = db
|
||||||
.lang_item(body.module(db.upcast()).krate(), LangItem::Future)
|
.lang_item(body.module(db.upcast()).krate(), LangItem::Future)
|
||||||
|
@ -1228,6 +1242,20 @@ impl HirDisplay for Ty {
|
||||||
SizedByDefault::Sized { anchor: krate },
|
SizedByDefault::Sized { anchor: krate },
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
ImplTraitId::AssociatedTypeImplTrait(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 bounds = data.substitute(Interner, &opaque_ty.substitution);
|
||||||
|
let krate = alias.krate(db.upcast());
|
||||||
|
write_bounds_like_dyn_trait_with_prefix(
|
||||||
|
f,
|
||||||
|
"impl",
|
||||||
|
bounds.skip_binders(),
|
||||||
|
SizedByDefault::Sized { anchor: krate },
|
||||||
|
)?;
|
||||||
|
}
|
||||||
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
||||||
write!(f, "{{async block}}")?;
|
write!(f, "{{async block}}")?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,11 @@ pub(crate) mod unify;
|
||||||
use std::{convert::identity, iter, ops::Index};
|
use std::{convert::identity, iter, ops::Index};
|
||||||
|
|
||||||
use chalk_ir::{
|
use chalk_ir::{
|
||||||
cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety,
|
cast::Cast,
|
||||||
Scalar, TyKind, TypeFlags, Variance,
|
fold::TypeFoldable,
|
||||||
|
interner::HasInterner,
|
||||||
|
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
|
||||||
|
DebruijnIndex, Mutability, Safety, Scalar, TyKind, TypeFlags, Variance,
|
||||||
};
|
};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
|
@ -53,14 +56,14 @@ use triomphe::Arc;
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
fold_tys,
|
fold_tys,
|
||||||
infer::coerce::CoerceMany,
|
infer::{coerce::CoerceMany, unify::InferenceTable},
|
||||||
lower::ImplTraitLoweringMode,
|
lower::ImplTraitLoweringMode,
|
||||||
static_lifetime, to_assoc_type_id,
|
static_lifetime, to_assoc_type_id,
|
||||||
traits::FnTrait,
|
traits::FnTrait,
|
||||||
utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
|
utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
|
||||||
AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
|
AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
|
||||||
InEnvironment, Interner, Lifetime, ProjectionTy, RpitId, Substitution, TraitEnvironment,
|
ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution,
|
||||||
TraitRef, Ty, TyBuilder, TyExt,
|
TraitEnvironment, Ty, TyBuilder, TyExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This lint has a false positive here. See the link below for details.
|
// This lint has a false positive here. See the link below for details.
|
||||||
|
@ -422,7 +425,7 @@ pub struct InferenceResult {
|
||||||
/// unresolved or missing subpatterns or subpatterns of mismatched types.
|
/// unresolved or missing subpatterns or subpatterns of mismatched types.
|
||||||
pub type_of_pat: ArenaMap<PatId, Ty>,
|
pub type_of_pat: ArenaMap<PatId, Ty>,
|
||||||
pub type_of_binding: ArenaMap<BindingId, Ty>,
|
pub type_of_binding: ArenaMap<BindingId, Ty>,
|
||||||
pub type_of_rpit: ArenaMap<RpitId, Ty>,
|
pub type_of_rpit: ArenaMap<ImplTraitIdx, Ty>,
|
||||||
/// Type of the result of `.into_iter()` on the for. `ExprId` is the one of the whole for loop.
|
/// Type of the result of `.into_iter()` on the for. `ExprId` is the one of the whole for loop.
|
||||||
pub type_of_for_iterator: FxHashMap<ExprId, Ty>,
|
pub type_of_for_iterator: FxHashMap<ExprId, Ty>,
|
||||||
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
||||||
|
@ -752,7 +755,12 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_const(&mut self, data: &ConstData) {
|
fn collect_const(&mut self, data: &ConstData) {
|
||||||
self.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.
|
||||||
|
self.insert_atpit_coercion_table(iter::once(&return_ty));
|
||||||
|
|
||||||
|
self.return_ty = return_ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_static(&mut self, data: &StaticData) {
|
fn collect_static(&mut self, data: &StaticData) {
|
||||||
|
@ -785,11 +793,13 @@ impl<'a> InferenceContext<'a> {
|
||||||
self.write_binding_ty(self_param, ty);
|
self.write_binding_ty(self_param, ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mut params_and_ret_tys = Vec::new();
|
||||||
for (ty, pat) in param_tys.zip(&*self.body.params) {
|
for (ty, pat) in param_tys.zip(&*self.body.params) {
|
||||||
let ty = self.insert_type_vars(ty);
|
let ty = self.insert_type_vars(ty);
|
||||||
let ty = self.normalize_associated_types_in(ty);
|
let ty = self.normalize_associated_types_in(ty);
|
||||||
|
|
||||||
self.infer_top_pat(*pat, &ty);
|
self.infer_top_pat(*pat, &ty);
|
||||||
|
params_and_ret_tys.push(ty);
|
||||||
}
|
}
|
||||||
let return_ty = &*data.ret_type;
|
let return_ty = &*data.ret_type;
|
||||||
|
|
||||||
|
@ -801,8 +811,11 @@ impl<'a> InferenceContext<'a> {
|
||||||
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
|
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
|
||||||
// RPIT opaque types use substitution of their parent function.
|
// RPIT opaque types use substitution of their parent function.
|
||||||
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
|
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
|
||||||
let result =
|
let result = self.insert_inference_vars_for_impl_trait(
|
||||||
self.insert_inference_vars_for_rpit(return_ty, rpits.clone(), fn_placeholders);
|
return_ty,
|
||||||
|
rpits.clone(),
|
||||||
|
fn_placeholders,
|
||||||
|
);
|
||||||
let rpits = rpits.skip_binders();
|
let rpits = rpits.skip_binders();
|
||||||
for (id, _) in rpits.impl_traits.iter() {
|
for (id, _) in rpits.impl_traits.iter() {
|
||||||
if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) {
|
if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) {
|
||||||
|
@ -817,13 +830,19 @@ 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.
|
||||||
|
// To define an ATPITs, that ATPIT must appear in the function's signitures.
|
||||||
|
// 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());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_inference_vars_for_rpit<T>(
|
fn insert_inference_vars_for_impl_trait<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
t: T,
|
t: T,
|
||||||
rpits: Arc<chalk_ir::Binders<crate::ReturnTypeImplTraits>>,
|
rpits: Arc<chalk_ir::Binders<crate::ImplTraits>>,
|
||||||
fn_placeholders: Substitution,
|
placeholders: Substitution,
|
||||||
) -> T
|
) -> T
|
||||||
where
|
where
|
||||||
T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>,
|
T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>,
|
||||||
|
@ -837,6 +856,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
};
|
};
|
||||||
let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
|
let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
|
||||||
ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
|
ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
|
||||||
|
ImplTraitId::AssociatedTypeImplTrait(_, idx) => idx,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let bounds =
|
let bounds =
|
||||||
|
@ -844,15 +864,14 @@ impl<'a> InferenceContext<'a> {
|
||||||
let var = self.table.new_type_var();
|
let var = self.table.new_type_var();
|
||||||
let var_subst = Substitution::from1(Interner, var.clone());
|
let var_subst = Substitution::from1(Interner, var.clone());
|
||||||
for bound in bounds {
|
for bound in bounds {
|
||||||
let predicate =
|
let predicate = bound.map(|it| it.cloned()).substitute(Interner, &placeholders);
|
||||||
bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders);
|
|
||||||
let (var_predicate, binders) =
|
let (var_predicate, binders) =
|
||||||
predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders();
|
predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders();
|
||||||
always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
|
always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
|
||||||
let var_predicate = self.insert_inference_vars_for_rpit(
|
let var_predicate = self.insert_inference_vars_for_impl_trait(
|
||||||
var_predicate,
|
var_predicate,
|
||||||
rpits.clone(),
|
rpits.clone(),
|
||||||
fn_placeholders.clone(),
|
placeholders.clone(),
|
||||||
);
|
);
|
||||||
self.push_obligation(var_predicate.cast(Interner));
|
self.push_obligation(var_predicate.cast(Interner));
|
||||||
}
|
}
|
||||||
|
@ -863,6 +882,106 @@ 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.
|
||||||
|
///
|
||||||
|
/// The inference var stretagy is effective because;
|
||||||
|
///
|
||||||
|
/// - It can still unify types that coerced into ATPIT
|
||||||
|
/// - 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> {
|
||||||
|
table: &'b mut InferenceTable<'a>,
|
||||||
|
opaque_tys: FxHashMap<OpaqueTyId, Ty>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> TypeVisitor<Interner> for OpaqueTyCollector<'a, 'b> {
|
||||||
|
type BreakTy = ();
|
||||||
|
|
||||||
|
fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interner(&self) -> Interner {
|
||||||
|
Interner
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_ty(
|
||||||
|
&mut self,
|
||||||
|
ty: &chalk_ir::Ty<Interner>,
|
||||||
|
outer_binder: DebruijnIndex,
|
||||||
|
) -> std::ops::ControlFlow<Self::BreakTy> {
|
||||||
|
let ty = self.table.resolve_ty_shallow(ty);
|
||||||
|
|
||||||
|
if let TyKind::OpaqueType(id, _) = ty.kind(Interner) {
|
||||||
|
self.opaque_tys.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 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);
|
||||||
|
}
|
||||||
|
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 atpits = self
|
||||||
|
.db
|
||||||
|
.type_alias_impl_traits(alias_id)
|
||||||
|
.expect("Marked as ATPIT but no impl traits!");
|
||||||
|
let alias_placeholders = TyBuilder::placeholder_subst(self.db, alias_id);
|
||||||
|
let ty = self.insert_inference_vars_for_impl_trait(
|
||||||
|
ty,
|
||||||
|
atpits,
|
||||||
|
alias_placeholders,
|
||||||
|
);
|
||||||
|
return Some((opaque_ty_id, ty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if !atpit_coercion_table.is_empty() {
|
||||||
|
self.table.atpit_coercion_table = Some(atpit_coercion_table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn infer_body(&mut self) {
|
fn infer_body(&mut self) {
|
||||||
match self.return_coercion {
|
match self.return_coercion {
|
||||||
Some(_) => self.infer_return(self.body.body_expr),
|
Some(_) => self.infer_return(self.body.body_expr),
|
||||||
|
|
|
@ -276,6 +276,23 @@ 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.
|
||||||
|
let mut to_ty = to_ty;
|
||||||
|
let mut _to = None;
|
||||||
|
if let Some(atpit_table) = &self.atpit_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) {
|
||||||
|
_to = Some(ty.clone());
|
||||||
|
to_ty = _to.as_ref().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Consider coercing the subtype to a DST
|
// Consider coercing the subtype to a DST
|
||||||
if let Ok(ret) = self.try_coerce_unsized(&from_ty, to_ty) {
|
if let Ok(ret) = self.try_coerce_unsized(&from_ty, to_ty) {
|
||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
|
|
|
@ -15,11 +15,11 @@ use crate::{
|
||||||
method_resolution::{self, VisibleFromModule},
|
method_resolution::{self, VisibleFromModule},
|
||||||
to_chalk_trait_id,
|
to_chalk_trait_id,
|
||||||
utils::generics,
|
utils::generics,
|
||||||
InferenceDiagnostic, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
|
InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
|
||||||
ValueTyDefId,
|
TyKind, ValueTyDefId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{ExprOrPatId, InferenceContext, TraitRef};
|
use super::{ExprOrPatId, InferenceContext};
|
||||||
|
|
||||||
impl InferenceContext<'_> {
|
impl InferenceContext<'_> {
|
||||||
pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty> {
|
pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty> {
|
||||||
|
|
|
@ -10,6 +10,7 @@ use chalk_solve::infer::ParameterEnaVariableExt;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use ena::unify::UnifyKey;
|
use ena::unify::UnifyKey;
|
||||||
use hir_expand::name;
|
use hir_expand::name;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
|
@ -18,8 +19,9 @@ use crate::{
|
||||||
consteval::unknown_const, db::HirDatabase, fold_tys_and_consts, static_lifetime,
|
consteval::unknown_const, db::HirDatabase, fold_tys_and_consts, static_lifetime,
|
||||||
to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue,
|
to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue,
|
||||||
DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData, Guidance, InEnvironment,
|
DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData, Guidance, InEnvironment,
|
||||||
InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution,
|
InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar,
|
||||||
Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause,
|
Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
|
||||||
|
WhereClause,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl InferenceContext<'_> {
|
impl InferenceContext<'_> {
|
||||||
|
@ -239,6 +241,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>>,
|
||||||
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>>>,
|
||||||
|
@ -258,6 +261,7 @@ impl<'a> InferenceTable<'a> {
|
||||||
InferenceTable {
|
InferenceTable {
|
||||||
db,
|
db,
|
||||||
trait_env,
|
trait_env,
|
||||||
|
atpit_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(),
|
||||||
|
|
|
@ -389,6 +389,9 @@ 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(..) => {
|
||||||
|
return Err(LayoutError::NotImplemented);
|
||||||
|
}
|
||||||
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
|
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
|
||||||
return Err(LayoutError::NotImplemented)
|
return Err(LayoutError::NotImplemented)
|
||||||
}
|
}
|
||||||
|
|
|
@ -584,24 +584,25 @@ 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, RpitId),
|
ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx),
|
||||||
|
AssociatedTypeImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
|
||||||
AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
|
AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
|
||||||
}
|
}
|
||||||
impl_intern_value_trivial!(ImplTraitId);
|
impl_intern_value_trivial!(ImplTraitId);
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct ReturnTypeImplTraits {
|
pub struct ImplTraits {
|
||||||
pub(crate) impl_traits: Arena<ReturnTypeImplTrait>,
|
pub(crate) impl_traits: Arena<ImplTrait>,
|
||||||
}
|
}
|
||||||
|
|
||||||
has_interner!(ReturnTypeImplTraits);
|
has_interner!(ImplTraits);
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct ReturnTypeImplTrait {
|
pub struct ImplTrait {
|
||||||
pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
|
pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type RpitId = Idx<ReturnTypeImplTrait>;
|
pub type ImplTraitIdx = Idx<ImplTrait>;
|
||||||
|
|
||||||
pub fn static_lifetime() -> Lifetime {
|
pub fn static_lifetime() -> Lifetime {
|
||||||
LifetimeData::Static.intern(Interner)
|
LifetimeData::Static.intern(Interner)
|
||||||
|
|
|
@ -61,9 +61,9 @@ use crate::{
|
||||||
InTypeConstIdMetadata,
|
InTypeConstIdMetadata,
|
||||||
},
|
},
|
||||||
AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy,
|
AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy,
|
||||||
FnAbi, FnPointer, FnSig, FnSubst, ImplTraitId, Interner, ParamKind, PolyFnSig, ProjectionTy,
|
FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, ParamKind,
|
||||||
QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits,
|
PolyFnSig, ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, Substitution,
|
||||||
Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
|
TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -76,7 +76,7 @@ enum ImplTraitLoweringState {
|
||||||
/// we're grouping the mutable data (the counter and this field) together
|
/// we're grouping the mutable data (the counter and this field) together
|
||||||
/// with the immutable context (the references to the DB and resolver).
|
/// with the immutable context (the references to the DB and resolver).
|
||||||
/// Splitting this up would be a possible fix.
|
/// Splitting this up would be a possible fix.
|
||||||
Opaque(RefCell<Arena<ReturnTypeImplTrait>>),
|
Opaque(RefCell<Arena<ImplTrait>>),
|
||||||
Param(Cell<u16>),
|
Param(Cell<u16>),
|
||||||
Variable(Cell<u16>),
|
Variable(Cell<u16>),
|
||||||
Disallowed,
|
Disallowed,
|
||||||
|
@ -301,15 +301,22 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
TypeRef::ImplTrait(bounds) => {
|
TypeRef::ImplTrait(bounds) => {
|
||||||
match &self.impl_trait_mode {
|
match &self.impl_trait_mode {
|
||||||
ImplTraitLoweringState::Opaque(opaque_type_data) => {
|
ImplTraitLoweringState::Opaque(opaque_type_data) => {
|
||||||
let func = match self.resolver.generic_def() {
|
let (origin, krate) = match self.resolver.generic_def() {
|
||||||
Some(GenericDefId::FunctionId(f)) => f,
|
Some(GenericDefId::FunctionId(f)) => {
|
||||||
_ => panic!("opaque impl trait lowering in non-function"),
|
(Either::Left(f), f.krate(self.db.upcast()))
|
||||||
|
}
|
||||||
|
Some(GenericDefId::TypeAliasId(a)) => {
|
||||||
|
(Either::Right(a), a.krate(self.db.upcast()))
|
||||||
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"opaque impl trait lowering must be in function or type alias"
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
// this dance is to make sure the data is in the right
|
// this dance is to make sure the data is in the right
|
||||||
// place even if we encounter more opaque types while
|
// place even if we encounter more opaque types while
|
||||||
// lowering the bounds
|
// lowering the bounds
|
||||||
let idx = opaque_type_data.borrow_mut().alloc(ReturnTypeImplTrait {
|
let idx = opaque_type_data.borrow_mut().alloc(ImplTrait {
|
||||||
bounds: crate::make_single_type_binders(Vec::new()),
|
bounds: crate::make_single_type_binders(Vec::new()),
|
||||||
});
|
});
|
||||||
// We don't want to lower the bounds inside the binders
|
// We don't want to lower the bounds inside the binders
|
||||||
|
@ -323,13 +330,17 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
// away instead of two.
|
// away instead of two.
|
||||||
let actual_opaque_type_data = self
|
let actual_opaque_type_data = self
|
||||||
.with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
|
.with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
|
||||||
ctx.lower_impl_trait(bounds, func)
|
ctx.lower_impl_trait(bounds, krate)
|
||||||
});
|
});
|
||||||
opaque_type_data.borrow_mut()[idx] = actual_opaque_type_data;
|
opaque_type_data.borrow_mut()[idx] = actual_opaque_type_data;
|
||||||
|
|
||||||
let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
|
let impl_trait_id = origin.either(
|
||||||
|
|f| ImplTraitId::ReturnTypeImplTrait(f, idx),
|
||||||
|
|a| ImplTraitId::AssociatedTypeImplTrait(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 = generics(self.db.upcast(), func.into());
|
let generics =
|
||||||
|
generics(self.db.upcast(), origin.either(|f| f.into(), |a| a.into()));
|
||||||
let parameters = generics.bound_vars_subst(self.db, self.in_binders);
|
let parameters = generics.bound_vars_subst(self.db, self.in_binders);
|
||||||
TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
|
TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
|
||||||
}
|
}
|
||||||
|
@ -1270,11 +1281,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_impl_trait(
|
fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>], krate: CrateId) -> ImplTrait {
|
||||||
&self,
|
|
||||||
bounds: &[Interned<TypeBound>],
|
|
||||||
func: FunctionId,
|
|
||||||
) -> ReturnTypeImplTrait {
|
|
||||||
cov_mark::hit!(lower_rpit);
|
cov_mark::hit!(lower_rpit);
|
||||||
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
||||||
let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
||||||
|
@ -1284,7 +1291,6 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if !ctx.unsized_types.borrow().contains(&self_ty) {
|
if !ctx.unsized_types.borrow().contains(&self_ty) {
|
||||||
let krate = func.krate(ctx.db.upcast());
|
|
||||||
let sized_trait = ctx
|
let sized_trait = ctx
|
||||||
.db
|
.db
|
||||||
.lang_item(krate, LangItem::Sized)
|
.lang_item(krate, LangItem::Sized)
|
||||||
|
@ -1301,7 +1307,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
}
|
}
|
||||||
predicates
|
predicates
|
||||||
});
|
});
|
||||||
ReturnTypeImplTrait { bounds: crate::make_single_type_binders(predicates) }
|
ImplTrait { bounds: crate::make_single_type_binders(predicates) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1869,6 +1875,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
|
||||||
let generics = generics(db.upcast(), t.into());
|
let generics = generics(db.upcast(), t.into());
|
||||||
let resolver = t.resolver(db.upcast());
|
let resolver = t.resolver(db.upcast());
|
||||||
let ctx = TyLoweringContext::new(db, &resolver, t.into())
|
let ctx = TyLoweringContext::new(db, &resolver, t.into())
|
||||||
|
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
|
||||||
.with_type_param_mode(ParamLoweringMode::Variable);
|
.with_type_param_mode(ParamLoweringMode::Variable);
|
||||||
let type_alias_data = db.type_alias_data(t);
|
let type_alias_data = db.type_alias_data(t);
|
||||||
if type_alias_data.is_extern {
|
if type_alias_data.is_extern {
|
||||||
|
@ -2029,7 +2036,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
|
||||||
pub(crate) fn return_type_impl_traits(
|
pub(crate) fn return_type_impl_traits(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
def: hir_def::FunctionId,
|
def: hir_def::FunctionId,
|
||||||
) -> Option<Arc<Binders<ReturnTypeImplTraits>>> {
|
) -> Option<Arc<Binders<ImplTraits>>> {
|
||||||
// FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
|
// FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
|
||||||
let data = db.function_data(def);
|
let data = db.function_data(def);
|
||||||
let resolver = def.resolver(db.upcast());
|
let resolver = def.resolver(db.upcast());
|
||||||
|
@ -2038,7 +2045,7 @@ pub(crate) fn return_type_impl_traits(
|
||||||
.with_type_param_mode(ParamLoweringMode::Variable);
|
.with_type_param_mode(ParamLoweringMode::Variable);
|
||||||
let _ret = ctx_ret.lower_ty(&data.ret_type);
|
let _ret = ctx_ret.lower_ty(&data.ret_type);
|
||||||
let generics = generics(db.upcast(), def.into());
|
let generics = generics(db.upcast(), def.into());
|
||||||
let return_type_impl_traits = ReturnTypeImplTraits {
|
let return_type_impl_traits = ImplTraits {
|
||||||
impl_traits: match ctx_ret.impl_trait_mode {
|
impl_traits: match ctx_ret.impl_trait_mode {
|
||||||
ImplTraitLoweringState::Opaque(x) => x.into_inner(),
|
ImplTraitLoweringState::Opaque(x) => x.into_inner(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -2051,6 +2058,32 @@ pub(crate) fn return_type_impl_traits(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn type_alias_impl_traits(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
def: hir_def::TypeAliasId,
|
||||||
|
) -> Option<Arc<Binders<ImplTraits>>> {
|
||||||
|
let data = db.type_alias_data(def);
|
||||||
|
let resolver = def.resolver(db.upcast());
|
||||||
|
let ctx = TyLoweringContext::new(db, &resolver, def.into())
|
||||||
|
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
|
||||||
|
.with_type_param_mode(ParamLoweringMode::Variable);
|
||||||
|
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(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if type_alias_impl_traits.impl_traits.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Arc::new(make_binders(db, &generics, type_alias_impl_traits)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
|
pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
|
||||||
match m {
|
match m {
|
||||||
hir_def::type_ref::Mutability::Shared => Mutability::Not,
|
hir_def::type_ref::Mutability::Shared => Mutability::Not,
|
||||||
|
|
|
@ -82,6 +82,9 @@ 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(..) => {
|
||||||
|
not_supported!("associated type impl trait");
|
||||||
|
}
|
||||||
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
|
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
|
||||||
not_supported!("async block impl trait");
|
not_supported!("async block impl trait");
|
||||||
}
|
}
|
||||||
|
|
|
@ -4655,3 +4655,78 @@ 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>>
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue