mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 05:15:04 +00:00
wip lower impl trait to type args
This commit is contained in:
parent
9dec65d3b1
commit
93aa166748
8 changed files with 97 additions and 14 deletions
|
@ -755,7 +755,7 @@ pub struct TypeParam {
|
||||||
impl TypeParam {
|
impl TypeParam {
|
||||||
pub fn name(self, db: &impl HirDatabase) -> Name {
|
pub fn name(self, db: &impl HirDatabase) -> Name {
|
||||||
let params = db.generic_params(self.id.parent);
|
let params = db.generic_params(self.id.parent);
|
||||||
params.types[self.id.local_id].name.clone()
|
params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module(self, db: &impl HirDatabase) -> Module {
|
pub fn module(self, db: &impl HirDatabase) -> Module {
|
||||||
|
|
|
@ -27,8 +27,16 @@ use crate::{
|
||||||
/// Data about a generic parameter (to a function, struct, impl, ...).
|
/// Data about a generic parameter (to a function, struct, impl, ...).
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct TypeParamData {
|
pub struct TypeParamData {
|
||||||
pub name: Name,
|
pub name: Option<Name>,
|
||||||
pub default: Option<TypeRef>,
|
pub default: Option<TypeRef>,
|
||||||
|
pub provenance: TypeParamProvenance,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub enum TypeParamProvenance {
|
||||||
|
TypeParamList,
|
||||||
|
TraitSelf,
|
||||||
|
ArgumentImplTrait,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data about the generic parameters of a function, struct, impl, etc.
|
/// Data about the generic parameters of a function, struct, impl, etc.
|
||||||
|
@ -68,6 +76,11 @@ impl GenericParams {
|
||||||
GenericDefId::FunctionId(it) => {
|
GenericDefId::FunctionId(it) => {
|
||||||
let src = it.lookup(db).source(db);
|
let src = it.lookup(db).source(db);
|
||||||
generics.fill(&mut sm, &src.value);
|
generics.fill(&mut sm, &src.value);
|
||||||
|
// lower `impl Trait` in arguments
|
||||||
|
let data = db.function_data(it);
|
||||||
|
for param in &data.params {
|
||||||
|
generics.fill_implicit_impl_trait_args(param);
|
||||||
|
}
|
||||||
src.file_id
|
src.file_id
|
||||||
}
|
}
|
||||||
GenericDefId::AdtId(AdtId::StructId(it)) => {
|
GenericDefId::AdtId(AdtId::StructId(it)) => {
|
||||||
|
@ -89,8 +102,11 @@ impl GenericParams {
|
||||||
let src = it.lookup(db).source(db);
|
let src = it.lookup(db).source(db);
|
||||||
|
|
||||||
// traits get the Self type as an implicit first type parameter
|
// traits get the Self type as an implicit first type parameter
|
||||||
let self_param_id =
|
let self_param_id = generics.types.alloc(TypeParamData {
|
||||||
generics.types.alloc(TypeParamData { name: name![Self], default: None });
|
name: Some(name![Self]),
|
||||||
|
default: None,
|
||||||
|
provenance: TypeParamProvenance::TraitSelf,
|
||||||
|
});
|
||||||
sm.insert(self_param_id, Either::Left(src.value.clone()));
|
sm.insert(self_param_id, Either::Left(src.value.clone()));
|
||||||
// add super traits as bounds on Self
|
// add super traits as bounds on Self
|
||||||
// i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
|
// i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
|
||||||
|
@ -142,7 +158,11 @@ impl GenericParams {
|
||||||
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
|
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
|
||||||
// FIXME: Use `Path::from_src`
|
// FIXME: Use `Path::from_src`
|
||||||
let default = type_param.default_type().map(TypeRef::from_ast);
|
let default = type_param.default_type().map(TypeRef::from_ast);
|
||||||
let param = TypeParamData { name: name.clone(), default };
|
let param = TypeParamData {
|
||||||
|
name: Some(name.clone()),
|
||||||
|
default,
|
||||||
|
provenance: TypeParamProvenance::TypeParamList,
|
||||||
|
};
|
||||||
let param_id = self.types.alloc(param);
|
let param_id = self.types.alloc(param);
|
||||||
sm.insert(param_id, Either::Right(type_param.clone()));
|
sm.insert(param_id, Either::Right(type_param.clone()));
|
||||||
|
|
||||||
|
@ -173,8 +193,23 @@ impl GenericParams {
|
||||||
self.where_predicates.push(WherePredicate { type_ref, bound });
|
self.where_predicates.push(WherePredicate { type_ref, bound });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
|
||||||
|
type_ref.walk(&mut |type_ref| {
|
||||||
|
if let TypeRef::ImplTrait(_) = type_ref {
|
||||||
|
let param = TypeParamData {
|
||||||
|
name: None,
|
||||||
|
default: None,
|
||||||
|
provenance: TypeParamProvenance::ArgumentImplTrait,
|
||||||
|
};
|
||||||
|
let _param_id = self.types.alloc(param);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
|
pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
|
||||||
self.types.iter().find_map(|(id, p)| if &p.name == name { Some(id) } else { None })
|
self.types
|
||||||
|
.iter()
|
||||||
|
.find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -490,12 +490,14 @@ impl Scope {
|
||||||
}
|
}
|
||||||
Scope::GenericParams { params, def } => {
|
Scope::GenericParams { params, def } => {
|
||||||
for (local_id, param) in params.types.iter() {
|
for (local_id, param) in params.types.iter() {
|
||||||
|
if let Some(name) = ¶m.name {
|
||||||
f(
|
f(
|
||||||
param.name.clone(),
|
name.clone(),
|
||||||
ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }),
|
ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Scope::ImplBlockScope(i) => {
|
Scope::ImplBlockScope(i) => {
|
||||||
f(name![Self], ScopeDef::ImplSelfType((*i).into()));
|
f(name![Self], ScopeDef::ImplSelfType((*i).into()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,6 +124,50 @@ impl TypeRef {
|
||||||
pub(crate) fn unit() -> TypeRef {
|
pub(crate) fn unit() -> TypeRef {
|
||||||
TypeRef::Tuple(Vec::new())
|
TypeRef::Tuple(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
|
||||||
|
go(self, f);
|
||||||
|
|
||||||
|
fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
|
||||||
|
f(type_ref);
|
||||||
|
match type_ref {
|
||||||
|
TypeRef::Fn(types) | TypeRef::Tuple(types) => {
|
||||||
|
types.iter().for_each(|t| go(t, f))
|
||||||
|
}
|
||||||
|
TypeRef::RawPtr(type_ref, _)
|
||||||
|
| TypeRef::Reference(type_ref, _)
|
||||||
|
| TypeRef::Array(type_ref)
|
||||||
|
| TypeRef::Slice(type_ref) => go(&type_ref, f),
|
||||||
|
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
|
||||||
|
for bound in bounds {
|
||||||
|
match bound {
|
||||||
|
TypeBound::Path(path) => go_path(path, f),
|
||||||
|
TypeBound::Error => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeRef::Path(path) => go_path(path, f),
|
||||||
|
TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
|
||||||
|
if let Some(type_ref) = path.type_anchor() {
|
||||||
|
go(type_ref, f);
|
||||||
|
}
|
||||||
|
for segment in path.segments().iter() {
|
||||||
|
if let Some(args_and_bindings) = segment.args_and_bindings {
|
||||||
|
for arg in &args_and_bindings.args {
|
||||||
|
let crate::path::GenericArg::Type(type_ref) = arg;
|
||||||
|
go(type_ref, f);
|
||||||
|
}
|
||||||
|
for (_, type_ref) in &args_and_bindings.bindings {
|
||||||
|
go(type_ref, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> {
|
pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use hir_def::{
|
||||||
resolver::resolver_for_expr,
|
resolver::resolver_for_expr,
|
||||||
AdtId, AssocContainerId, Lookup, StructFieldId,
|
AdtId, AssocContainerId, Lookup, StructFieldId,
|
||||||
};
|
};
|
||||||
use hir_expand::name::{name, Name};
|
use hir_expand::name::Name;
|
||||||
use ra_syntax::ast::RangeOp;
|
use ra_syntax::ast::RangeOp;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -654,7 +654,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
// Parent arguments are unknown, except for the receiver type
|
// Parent arguments are unknown, except for the receiver type
|
||||||
if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
|
if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
|
||||||
for (_id, param) in parent_generics {
|
for (_id, param) in parent_generics {
|
||||||
if param.name == name![Self] {
|
if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf {
|
||||||
substs.push(receiver_ty.clone());
|
substs.push(receiver_ty.clone());
|
||||||
} else {
|
} else {
|
||||||
substs.push(Ty::Unknown);
|
substs.push(Ty::Unknown);
|
||||||
|
|
|
@ -368,7 +368,7 @@ impl Substs {
|
||||||
/// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
|
/// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
|
||||||
pub(crate) fn identity(generic_params: &Generics) -> Substs {
|
pub(crate) fn identity(generic_params: &Generics) -> Substs {
|
||||||
Substs(
|
Substs(
|
||||||
generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone() }).collect(),
|
generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone().unwrap_or_else(Name::missing) }).collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -341,6 +341,7 @@ pub(super) fn substs_from_path_segment(
|
||||||
// Self type as an implicit first type parameter, but it can't be
|
// Self type as an implicit first type parameter, but it can't be
|
||||||
// actually provided in the type arguments
|
// actually provided in the type arguments
|
||||||
// (well, actually sometimes it can, in the form of type-relative paths: `<Foo as Default>::default()`)
|
// (well, actually sometimes it can, in the form of type-relative paths: `<Foo as Default>::default()`)
|
||||||
|
// TODO handle this using type param provenance
|
||||||
substs.push(Ty::Unknown);
|
substs.push(Ty::Unknown);
|
||||||
}
|
}
|
||||||
if let Some(generic_args) = &segment.args_and_bindings {
|
if let Some(generic_args) = &segment.args_and_bindings {
|
||||||
|
|
|
@ -127,7 +127,8 @@ impl Generics {
|
||||||
self.find_param(param).0
|
self.find_param(param).0
|
||||||
}
|
}
|
||||||
pub(crate) fn param_name(&self, param: TypeParamId) -> Name {
|
pub(crate) fn param_name(&self, param: TypeParamId) -> Name {
|
||||||
self.find_param(param).1.name.clone()
|
// FIXME make this return Option
|
||||||
|
self.find_param(param).1.name.clone().unwrap_or_else(Name::missing)
|
||||||
}
|
}
|
||||||
fn find_param(&self, param: TypeParamId) -> (u32, &TypeParamData) {
|
fn find_param(&self, param: TypeParamId) -> (u32, &TypeParamData) {
|
||||||
if param.parent == self.def {
|
if param.parent == self.def {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue