mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
implement creating generics for impl traits in associated types
This commit is contained in:
parent
f216be4a07
commit
40a677ddf0
6 changed files with 102 additions and 17 deletions
|
@ -339,6 +339,7 @@ impl GenericParamsCollector {
|
||||||
target: Either<TypeRef, LifetimeRef>,
|
target: Either<TypeRef, LifetimeRef>,
|
||||||
) {
|
) {
|
||||||
let bound = TypeBound::from_ast(lower_ctx, bound);
|
let bound = TypeBound::from_ast(lower_ctx, bound);
|
||||||
|
self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
|
||||||
let predicate = match (target, bound) {
|
let predicate = match (target, bound) {
|
||||||
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
|
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
|
||||||
Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
|
Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
|
||||||
|
@ -359,6 +360,23 @@ impl GenericParamsCollector {
|
||||||
self.where_predicates.push(predicate);
|
self.where_predicates.push(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) {
|
||||||
|
for bounds in impl_bounds {
|
||||||
|
let param = TypeParamData {
|
||||||
|
name: None,
|
||||||
|
default: None,
|
||||||
|
provenance: TypeParamProvenance::ArgumentImplTrait,
|
||||||
|
};
|
||||||
|
let param_id = self.type_or_consts.alloc(param.into());
|
||||||
|
for bound in bounds {
|
||||||
|
self.where_predicates.push(WherePredicate::TypeBound {
|
||||||
|
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
|
||||||
|
bound,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn fill_implicit_impl_trait_args(
|
pub(crate) fn fill_implicit_impl_trait_args(
|
||||||
&mut self,
|
&mut self,
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
|
|
|
@ -1,26 +1,34 @@
|
||||||
//! Context for lowering paths.
|
//! Context for lowering paths.
|
||||||
use std::cell::OnceCell;
|
use std::cell::{OnceCell, RefCell};
|
||||||
|
|
||||||
use hir_expand::{
|
use hir_expand::{
|
||||||
span_map::{SpanMap, SpanMapRef},
|
span_map::{SpanMap, SpanMapRef},
|
||||||
AstId, HirFileId, InFile,
|
AstId, HirFileId, InFile,
|
||||||
};
|
};
|
||||||
|
use intern::Interned;
|
||||||
use span::{AstIdMap, AstIdNode};
|
use span::{AstIdMap, AstIdNode};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
use crate::{db::DefDatabase, path::Path};
|
use crate::{db::DefDatabase, path::Path, type_ref::TypeBound};
|
||||||
|
|
||||||
pub struct LowerCtx<'a> {
|
pub struct LowerCtx<'a> {
|
||||||
pub db: &'a dyn DefDatabase,
|
pub db: &'a dyn DefDatabase,
|
||||||
file_id: HirFileId,
|
file_id: HirFileId,
|
||||||
span_map: OnceCell<SpanMap>,
|
span_map: OnceCell<SpanMap>,
|
||||||
ast_id_map: OnceCell<Arc<AstIdMap>>,
|
ast_id_map: OnceCell<Arc<AstIdMap>>,
|
||||||
|
impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LowerCtx<'a> {
|
impl<'a> LowerCtx<'a> {
|
||||||
pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
|
pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
|
||||||
LowerCtx { db, file_id, span_map: OnceCell::new(), ast_id_map: OnceCell::new() }
|
LowerCtx {
|
||||||
|
db,
|
||||||
|
file_id,
|
||||||
|
span_map: OnceCell::new(),
|
||||||
|
ast_id_map: OnceCell::new(),
|
||||||
|
impl_trait_bounds: RefCell::new(Vec::new()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_span_map_cell(
|
pub fn with_span_map_cell(
|
||||||
|
@ -28,7 +36,13 @@ impl<'a> LowerCtx<'a> {
|
||||||
file_id: HirFileId,
|
file_id: HirFileId,
|
||||||
span_map: OnceCell<SpanMap>,
|
span_map: OnceCell<SpanMap>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
LowerCtx { db, file_id, span_map, ast_id_map: OnceCell::new() }
|
LowerCtx {
|
||||||
|
db,
|
||||||
|
file_id,
|
||||||
|
span_map,
|
||||||
|
ast_id_map: OnceCell::new(),
|
||||||
|
impl_trait_bounds: RefCell::new(Vec::new()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
|
pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
|
||||||
|
@ -45,4 +59,12 @@ impl<'a> LowerCtx<'a> {
|
||||||
self.ast_id_map.get_or_init(|| self.db.ast_id_map(self.file_id)).ast_id(item),
|
self.ast_id_map.get_or_init(|| self.db.ast_id_map(self.file_id)).ast_id(item),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) {
|
||||||
|
self.impl_trait_bounds.borrow_mut().push(bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> {
|
||||||
|
self.impl_trait_bounds.borrow_mut().drain(..).collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,6 +208,13 @@ pub(super) fn lower_generic_args(
|
||||||
.and_then(|args| lower_generic_args(lower_ctx, args))
|
.and_then(|args| lower_generic_args(lower_ctx, args))
|
||||||
.map(Interned::new);
|
.map(Interned::new);
|
||||||
let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
|
let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
|
||||||
|
let type_ref = type_ref.inspect(|tr| {
|
||||||
|
tr.walk(&mut |tr| {
|
||||||
|
if let TypeRef::ImplTrait(bounds) = tr {
|
||||||
|
lower_ctx.update_impl_traits_bounds(bounds.clone());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
|
let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
|
||||||
l.bounds()
|
l.bounds()
|
||||||
.map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
|
.map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! Name resolution façade.
|
//! Name resolution façade.
|
||||||
use std::{fmt, hash::BuildHasherDefault, mem};
|
use std::{fmt, hash::BuildHasherDefault, iter, mem};
|
||||||
|
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use hir_expand::{
|
use hir_expand::{
|
||||||
|
@ -591,13 +591,13 @@ impl Resolver {
|
||||||
|
|
||||||
pub fn where_predicates_in_scope(
|
pub fn where_predicates_in_scope(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = &crate::generics::WherePredicate> {
|
) -> impl Iterator<Item = (&crate::generics::WherePredicate, &GenericDefId)> {
|
||||||
self.scopes()
|
self.scopes()
|
||||||
.filter_map(|scope| match scope {
|
.filter_map(|scope| match scope {
|
||||||
Scope::GenericParams { params, .. } => Some(params),
|
Scope::GenericParams { params, def } => Some((params, def)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.flat_map(|params| params.where_predicates.iter())
|
.flat_map(|(params, def)| params.where_predicates.iter().zip(iter::repeat(def)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generic_def(&self) -> Option<GenericDefId> {
|
pub fn generic_def(&self) -> Option<GenericDefId> {
|
||||||
|
|
|
@ -1010,6 +1010,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
pub(crate) fn lower_where_predicate<'b>(
|
pub(crate) fn lower_where_predicate<'b>(
|
||||||
&'b self,
|
&'b self,
|
||||||
where_predicate: &'b WherePredicate,
|
where_predicate: &'b WherePredicate,
|
||||||
|
&def: &GenericDefId,
|
||||||
ignore_bindings: bool,
|
ignore_bindings: bool,
|
||||||
) -> impl Iterator<Item = QuantifiedWhereClause> + 'b {
|
) -> impl Iterator<Item = QuantifiedWhereClause> + 'b {
|
||||||
match where_predicate {
|
match where_predicate {
|
||||||
|
@ -1018,7 +1019,6 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
let self_ty = match target {
|
let self_ty = match target {
|
||||||
WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
|
WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
|
||||||
&WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
|
&WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
|
||||||
let def = self.resolver.generic_def().expect("generics in scope");
|
|
||||||
let param_id = hir_def::TypeOrConstParamId { parent: def, local_id };
|
let param_id = hir_def::TypeOrConstParamId { parent: def, local_id };
|
||||||
match self.type_param_mode {
|
match self.type_param_mode {
|
||||||
ParamLoweringMode::Placeholder => {
|
ParamLoweringMode::Placeholder => {
|
||||||
|
@ -1178,7 +1178,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
let target_param_idx = self
|
let target_param_idx = self
|
||||||
.resolver
|
.resolver
|
||||||
.where_predicates_in_scope()
|
.where_predicates_in_scope()
|
||||||
.find_map(|p| match p {
|
.find_map(|(p, _)| match p {
|
||||||
WherePredicate::TypeBound {
|
WherePredicate::TypeBound {
|
||||||
target: WherePredicateTypeTarget::TypeOrConstParam(idx),
|
target: WherePredicateTypeTarget::TypeOrConstParam(idx),
|
||||||
bound: b,
|
bound: b,
|
||||||
|
@ -1559,7 +1559,7 @@ pub(crate) fn generic_predicates_for_param_query(
|
||||||
let generics = generics(db.upcast(), def);
|
let generics = generics(db.upcast(), def);
|
||||||
|
|
||||||
// we have to filter out all other predicates *first*, before attempting to lower them
|
// we have to filter out all other predicates *first*, before attempting to lower them
|
||||||
let predicate = |pred: &&_| match pred {
|
let predicate = |(pred, &def): &(&_, _)| match pred {
|
||||||
WherePredicate::ForLifetime { target, bound, .. }
|
WherePredicate::ForLifetime { target, bound, .. }
|
||||||
| WherePredicate::TypeBound { target, bound, .. } => {
|
| WherePredicate::TypeBound { target, bound, .. } => {
|
||||||
let invalid_target = match target {
|
let invalid_target = match target {
|
||||||
|
@ -1601,8 +1601,8 @@ pub(crate) fn generic_predicates_for_param_query(
|
||||||
let mut predicates: Vec<_> = resolver
|
let mut predicates: Vec<_> = resolver
|
||||||
.where_predicates_in_scope()
|
.where_predicates_in_scope()
|
||||||
.filter(predicate)
|
.filter(predicate)
|
||||||
.flat_map(|pred| {
|
.flat_map(|(pred, def)| {
|
||||||
ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p))
|
ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -1655,8 +1655,8 @@ pub(crate) fn trait_environment_query(
|
||||||
};
|
};
|
||||||
let mut traits_in_scope = Vec::new();
|
let mut traits_in_scope = Vec::new();
|
||||||
let mut clauses = Vec::new();
|
let mut clauses = Vec::new();
|
||||||
for pred in resolver.where_predicates_in_scope() {
|
for (pred, def) in resolver.where_predicates_in_scope() {
|
||||||
for pred in ctx.lower_where_predicate(pred, false) {
|
for pred in ctx.lower_where_predicate(pred, def, false) {
|
||||||
if let WhereClause::Implemented(tr) = &pred.skip_binders() {
|
if let WhereClause::Implemented(tr) = &pred.skip_binders() {
|
||||||
traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
|
traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
|
||||||
}
|
}
|
||||||
|
@ -1710,8 +1710,8 @@ pub(crate) fn generic_predicates_query(
|
||||||
|
|
||||||
let mut predicates = resolver
|
let mut predicates = resolver
|
||||||
.where_predicates_in_scope()
|
.where_predicates_in_scope()
|
||||||
.flat_map(|pred| {
|
.flat_map(|(pred, def)| {
|
||||||
ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p))
|
ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
|
|
@ -4765,3 +4765,41 @@ fn test() {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue