11140: Preserve order of generic args r=HKalbasi a=HKalbasi

https://github.com/rust-lang/rust/pull/90207 removed order restriction of generic args, i.e. const generics can now become before of type generics. We need to preserve this order to analyze correctly, and this PR does that.

It also simplifies implementation of const generics a bit IMO.

Implementing default generics the same problem of #7434, we need lower them to body and then evaluate them.


Co-authored-by: hkalbasi <hamidrezakalbasi@protonmail.com>
This commit is contained in:
bors[bot] 2022-03-04 12:55:07 +00:00 committed by GitHub
commit f8329ba987
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 712 additions and 424 deletions

View File

@ -139,9 +139,9 @@ fn resolve_doc_path(
AttrDefId::ImplId(it) => it.resolver(db.upcast()),
AttrDefId::ExternBlockId(it) => it.resolver(db.upcast()),
AttrDefId::GenericParamId(it) => match it {
GenericParamId::TypeParamId(it) => it.parent,
GenericParamId::TypeParamId(it) => it.parent(),
GenericParamId::ConstParamId(it) => it.parent(),
GenericParamId::LifetimeParamId(it) => it.parent,
GenericParamId::ConstParamId(it) => it.parent,
}
.resolver(db.upcast()),
// FIXME

View File

@ -1,7 +1,9 @@
//! HirDisplay implementations for various hir types.
use hir_def::{
adt::VariantData,
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
generics::{
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
},
type_ref::{TypeBound, TypeRef},
AdtId, GenericDefId,
};
@ -16,8 +18,8 @@ use syntax::SmolStr;
use crate::{
Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
LifetimeParam, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, TypeParam, Union,
Variant,
LifetimeParam, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, TypeOrConstParam,
TypeParam, Union, Variant,
};
impl HirDisplay for Function {
@ -226,8 +228,17 @@ impl HirDisplay for GenericParam {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
match self {
GenericParam::TypeParam(it) => it.hir_fmt(f),
GenericParam::LifetimeParam(it) => it.hir_fmt(f),
GenericParam::ConstParam(it) => it.hir_fmt(f),
GenericParam::LifetimeParam(it) => it.hir_fmt(f),
}
}
}
impl HirDisplay for TypeOrConstParam {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
match self.split(f.db) {
either::Either::Left(x) => x.hir_fmt(f),
either::Either::Right(x) => x.hir_fmt(f),
}
}
}
@ -239,11 +250,11 @@ impl HirDisplay for TypeParam {
return Ok(());
}
let bounds = f.db.generic_predicates_for_param(self.id.parent, self.id, None);
let substs = TyBuilder::type_params_subst(f.db, self.id.parent);
let bounds = f.db.generic_predicates_for_param(self.id.parent(), self.id.into(), None);
let substs = TyBuilder::type_params_subst(f.db, self.id.parent());
let predicates: Vec<_> =
bounds.iter().cloned().map(|b| b.substitute(Interner, &substs)).collect();
let krate = self.id.parent.krate(f.db).id;
let krate = self.id.parent().krate(f.db).id;
let sized_trait =
f.db.lang_item(krate, SmolStr::new_inline("sized"))
.and_then(|lang_item| lang_item.as_trait());
@ -276,11 +287,11 @@ impl HirDisplay for ConstParam {
fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
let params = f.db.generic_params(def);
if params.lifetimes.is_empty()
&& params.consts.is_empty()
&& params
.types
.iter()
.all(|(_, param)| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
.filter_map(|x| x.1.type_param())
.all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
{
return Ok(());
}
@ -300,23 +311,27 @@ fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), H
write!(f, "{}", lifetime.name)?;
}
for (_, ty) in params.types.iter() {
if ty.provenance != TypeParamProvenance::TypeParamList {
continue;
}
if let Some(name) = &ty.name {
delim(f)?;
write!(f, "{}", name)?;
if let Some(default) = &ty.default {
write!(f, " = ")?;
default.hir_fmt(f)?;
if let Some(name) = &ty.name() {
match ty {
TypeOrConstParamData::TypeParamData(ty) => {
if ty.provenance != TypeParamProvenance::TypeParamList {
continue;
}
delim(f)?;
write!(f, "{}", name)?;
if let Some(default) = &ty.default {
write!(f, " = ")?;
default.hir_fmt(f)?;
}
}
TypeOrConstParamData::ConstParamData(c) => {
delim(f)?;
write!(f, "const {}: ", name)?;
c.ty.hir_fmt(f)?;
}
}
}
}
for (_, konst) in params.consts.iter() {
delim(f)?;
write!(f, "const {}: ", konst.name)?;
konst.ty.hir_fmt(f)?;
}
write!(f, ">")?;
Ok(())
@ -328,7 +343,7 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), Hir
// unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target {
WherePredicateTypeTarget::TypeRef(_) => false,
WherePredicateTypeTarget::TypeParam(id) => params.types[*id].name.is_none(),
WherePredicateTypeTarget::TypeOrConstParam(id) => params.types[*id].name().is_none(),
};
let has_displayable_predicate = params
@ -344,7 +359,7 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), Hir
let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter| match target {
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
WherePredicateTypeTarget::TypeParam(id) => match &params.types[*id].name {
WherePredicateTypeTarget::TypeOrConstParam(id) => match &params.types[*id].name() {
Some(name) => write!(f, "{}", name),
None => write!(f, "{{unnamed}}"),
},

View File

@ -41,9 +41,10 @@ from_id![
(hir_def::ConstId, crate::Const),
(hir_def::FunctionId, crate::Function),
(hir_def::ImplId, crate::Impl),
(hir_def::TypeOrConstParamId, crate::TypeOrConstParam),
(hir_def::TypeParamId, crate::TypeParam),
(hir_def::LifetimeParamId, crate::LifetimeParam),
(hir_def::ConstParamId, crate::ConstParam),
(hir_def::LifetimeParamId, crate::LifetimeParam),
(hir_expand::MacroDefId, crate::MacroDef)
];
@ -71,8 +72,8 @@ impl From<GenericParamId> for GenericParam {
fn from(id: GenericParamId) -> Self {
match id {
GenericParamId::TypeParamId(it) => GenericParam::TypeParam(it.into()),
GenericParamId::LifetimeParamId(it) => GenericParam::LifetimeParam(it.into()),
GenericParamId::ConstParamId(it) => GenericParam::ConstParam(it.into()),
GenericParamId::LifetimeParamId(it) => GenericParam::LifetimeParam(it.into()),
}
}
}
@ -80,9 +81,9 @@ impl From<GenericParamId> for GenericParam {
impl From<GenericParam> for GenericParamId {
fn from(id: GenericParam) -> Self {
match id {
GenericParam::TypeParam(it) => GenericParamId::TypeParamId(it.id),
GenericParam::LifetimeParam(it) => GenericParamId::LifetimeParamId(it.id),
GenericParam::ConstParam(it) => GenericParamId::ConstParamId(it.id),
GenericParam::ConstParam(it) => GenericParamId::ConstParamId(it.id.into()),
GenericParam::TypeParam(it) => GenericParamId::TypeParamId(it.id.into()),
}
}
}

View File

@ -10,8 +10,8 @@ use hir_expand::InFile;
use syntax::ast;
use crate::{
db::HirDatabase, Adt, Const, ConstParam, Enum, Field, FieldSource, Function, Impl,
LifetimeParam, MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
db::HirDatabase, Adt, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam, MacroDef,
Module, Static, Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant,
};
pub trait HasSource {
@ -139,8 +139,8 @@ impl HasSource for Impl {
}
}
impl HasSource for TypeParam {
type Ast = Either<ast::TypeParam, ast::Trait>;
impl HasSource for TypeOrConstParam {
type Ast = Either<ast::TypeOrConstParam, ast::Trait>;
fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
let child_source = self.id.parent.child_source(db.upcast());
Some(child_source.map(|it| it[self.id.local_id].clone()))
@ -154,11 +154,3 @@ impl HasSource for LifetimeParam {
Some(child_source.map(|it| it[self.id.local_id].clone()))
}
}
impl HasSource for ConstParam {
type Ast = ast::ConstParam;
fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
let child_source = self.id.parent.child_source(db.upcast());
Some(child_source.map(|it| it[self.id.local_id].clone()))
}
}

View File

@ -50,7 +50,7 @@ use hir_def::{
AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
TypeParamId, UnionId,
TypeOrConstParamId, TypeParamId, UnionId,
};
use hir_expand::{name::name, MacroCallKind, MacroDefId, MacroDefKind};
use hir_ty::{
@ -71,7 +71,7 @@ use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind;
use once_cell::unsync::Lazy;
use rustc_hash::FxHashSet;
use stdx::{format_to, impl_from};
use stdx::{format_to, impl_from, never};
use syntax::{
ast::{self, HasAttrs as _, HasDocComments, HasName},
AstNode, AstPtr, SmolStr, SyntaxNodePtr, T,
@ -2007,11 +2007,13 @@ impl_from!(
impl GenericDef {
pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
let generics = db.generic_params(self.into());
let ty_params = generics
.types
.iter()
.map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } })
.map(GenericParam::TypeParam);
let ty_params = generics.types.iter().map(|(local_id, _)| {
let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
match toc.split(db) {
Either::Left(x) => GenericParam::ConstParam(x),
Either::Right(x) => GenericParam::TypeParam(x),
}
});
let lt_params = generics
.lifetimes
.iter()
@ -2019,20 +2021,17 @@ impl GenericDef {
id: LifetimeParamId { parent: self.into(), local_id },
})
.map(GenericParam::LifetimeParam);
let const_params = generics
.consts
.iter()
.map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } })
.map(GenericParam::ConstParam);
ty_params.chain(lt_params).chain(const_params).collect()
ty_params.chain(lt_params).collect()
}
pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> {
pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
let generics = db.generic_params(self.into());
generics
.types
.iter()
.map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } })
.map(|(local_id, _)| TypeOrConstParam {
id: TypeOrConstParamId { parent: self.into(), local_id },
})
.collect()
}
}
@ -2221,25 +2220,25 @@ impl Label {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum GenericParam {
TypeParam(TypeParam),
LifetimeParam(LifetimeParam),
ConstParam(ConstParam),
LifetimeParam(LifetimeParam),
}
impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam);
impl_from!(TypeParam, ConstParam, LifetimeParam for GenericParam);
impl GenericParam {
pub fn module(self, db: &dyn HirDatabase) -> Module {
match self {
GenericParam::TypeParam(it) => it.module(db),
GenericParam::LifetimeParam(it) => it.module(db),
GenericParam::ConstParam(it) => it.module(db),
GenericParam::LifetimeParam(it) => it.module(db),
}
}
pub fn name(self, db: &dyn HirDatabase) -> Name {
match self {
GenericParam::TypeParam(it) => it.name(db),
GenericParam::LifetimeParam(it) => it.name(db),
GenericParam::ConstParam(it) => it.name(db),
GenericParam::LifetimeParam(it) => it.name(db),
}
}
}
@ -2250,19 +2249,23 @@ pub struct TypeParam {
}
impl TypeParam {
pub fn merge(self) -> TypeOrConstParam {
TypeOrConstParam { id: self.id.into() }
}
pub fn name(self, db: &dyn HirDatabase) -> Name {
let params = db.generic_params(self.id.parent);
params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing)
self.merge().name(db)
}
pub fn module(self, db: &dyn HirDatabase) -> Module {
self.id.parent.module(db.upcast()).into()
self.id.parent().module(db.upcast()).into()
}
pub fn ty(self, db: &dyn HirDatabase) -> Type {
let resolver = self.id.parent.resolver(db.upcast());
let krate = self.id.parent.module(db.upcast()).krate();
let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id)).intern(Interner);
let resolver = self.id.parent().resolver(db.upcast());
let krate = self.id.parent().module(db.upcast()).krate();
let ty =
TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id.into())).intern(Interner);
Type::new_with_resolver_inner(db, krate, &resolver, ty)
}
@ -2270,7 +2273,7 @@ impl TypeParam {
/// parameter, not additional bounds that might be added e.g. by a method if
/// the parameter comes from an impl!
pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
db.generic_predicates_for_param(self.id.parent, self.id, None)
db.generic_predicates_for_param(self.id.parent(), self.id.into(), None)
.iter()
.filter_map(|pred| match &pred.skip_binders().skip_binders() {
hir_ty::WhereClause::Implemented(trait_ref) => {
@ -2282,12 +2285,12 @@ impl TypeParam {
}
pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
let params = db.generic_defaults(self.id.parent);
let local_idx = hir_ty::param_idx(db, self.id)?;
let resolver = self.id.parent.resolver(db.upcast());
let krate = self.id.parent.module(db.upcast()).krate();
let params = db.generic_defaults(self.id.parent());
let local_idx = hir_ty::param_idx(db, self.id.into())?;
let resolver = self.id.parent().resolver(db.upcast());
let krate = self.id.parent().module(db.upcast()).krate();
let ty = params.get(local_idx)?.clone();
let subst = TyBuilder::type_params_subst(db, self.id.parent);
let subst = TyBuilder::type_params_subst(db, self.id.parent());
let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
Some(Type::new_with_resolver_inner(db, krate, &resolver, ty))
}
@ -2319,9 +2322,48 @@ pub struct ConstParam {
}
impl ConstParam {
pub fn merge(self) -> TypeOrConstParam {
TypeOrConstParam { id: self.id.into() }
}
pub fn name(self, db: &dyn HirDatabase) -> Name {
let params = db.generic_params(self.id.parent());
match params.types[self.id.local_id()].name() {
Some(x) => x.clone(),
None => {
never!();
Name::missing()
}
}
}
pub fn module(self, db: &dyn HirDatabase) -> Module {
self.id.parent().module(db.upcast()).into()
}
pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
self.id.parent().into()
}
pub fn ty(self, db: &dyn HirDatabase) -> Type {
let def = self.id.parent();
let krate = def.module(db.upcast()).krate();
Type::new(db, krate, def, db.const_param_ty(self.id))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct TypeOrConstParam {
pub(crate) id: TypeOrConstParamId,
}
impl TypeOrConstParam {
pub fn name(self, db: &dyn HirDatabase) -> Name {
let params = db.generic_params(self.id.parent);
params.consts[self.id.local_id].name.clone()
match params.types[self.id.local_id].name() {
Some(n) => n.clone(),
_ => Name::missing(),
}
}
pub fn module(self, db: &dyn HirDatabase) -> Module {
@ -2332,10 +2374,23 @@ impl ConstParam {
self.id.parent.into()
}
pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> {
let params = db.generic_params(self.id.parent);
match &params.types[self.id.local_id] {
hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
Either::Right(TypeParam { id: self.id.into() })
}
hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
Either::Left(ConstParam { id: self.id.into() })
}
}
}
pub fn ty(self, db: &dyn HirDatabase) -> Type {
let def = self.id.parent;
let krate = def.module(db.upcast()).krate();
Type::new(db, krate, def, db.const_param_ty(self.id))
match self.split(db) {
Either::Left(x) => x.ty(db),
Either::Right(x) => x.ty(db),
}
}
}

View File

@ -282,7 +282,7 @@ impl SourceToDefCtx<'_, '_> {
pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> {
let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
let dyn_map = self.cache_for(container, src.file_id);
dyn_map[keys::TYPE_PARAM].get(&src.value).copied()
dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|x| x.into())
}
pub(super) fn lifetime_param_to_def(
@ -300,7 +300,7 @@ impl SourceToDefCtx<'_, '_> {
) -> Option<ConstParamId> {
let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
let dyn_map = self.cache_for(container, src.file_id);
dyn_map[keys::CONST_PARAM].get(&src.value).copied()
dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(|x| x.into())
}
pub(super) fn generic_param_to_def(

View File

@ -34,7 +34,7 @@ use syntax::{
use crate::{
db::HirDatabase, semantics::PathResolution, Adt, BuiltinAttr, BuiltinType, Const, Field,
Function, Local, MacroDef, ModuleDef, Static, Struct, ToolModule, Trait, Type, TypeAlias,
TypeParam, Variant,
Variant,
};
use base_db::CrateId;
@ -609,7 +609,7 @@ fn resolve_hir_path_(
let res = match ty {
TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
PathResolution::Def(Adt::from(it).into())
}
@ -650,7 +650,7 @@ fn resolve_hir_path_(
ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()),
ValueNs::GenericParam(it) => PathResolution::ConstParam(it.into()),
ValueNs::GenericParam(id) => PathResolution::ConstParam(id.into()),
};
Some(res)
})
@ -703,7 +703,7 @@ fn resolve_hir_path_qualifier(
resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty {
TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => PathResolution::Def(Adt::from(it).into()),
TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),

View File

@ -367,23 +367,36 @@ impl AttrsWithOwner {
AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
AttrDefId::GenericParamId(it) => match it {
GenericParamId::TypeParamId(it) => {
let src = it.parent.child_source(db);
GenericParamId::ConstParamId(it) => {
let src = it.parent().child_source(db);
RawAttrs::from_attrs_owner(
db,
src.with_value(
src.value[it.local_id].as_ref().either(|it| it as _, |it| it as _),
),
src.with_value(src.value[it.local_id()].as_ref().either(
|it| match it {
ast::TypeOrConstParam::Type(it) => it as _,
ast::TypeOrConstParam::Const(it) => it as _,
},
|it| it as _,
)),
)
}
GenericParamId::TypeParamId(it) => {
let src = it.parent().child_source(db);
RawAttrs::from_attrs_owner(
db,
src.with_value(src.value[it.local_id()].as_ref().either(
|it| match it {
ast::TypeOrConstParam::Type(it) => it as _,
ast::TypeOrConstParam::Const(it) => it as _,
},
|it| it as _,
)),
)
}
GenericParamId::LifetimeParamId(it) => {
let src = it.parent.child_source(db);
RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
}
GenericParamId::ConstParamId(it) => {
let src = it.parent.child_source(db);
RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
}
},
AttrDefId::ExternBlockId(it) => attrs_from_item_tree(it.lookup(db).id, db),
};
@ -454,9 +467,25 @@ impl AttrsWithOwner {
),
AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
AttrDefId::GenericParamId(id) => match id {
GenericParamId::ConstParamId(id) => {
id.parent().child_source(db).map(|source| match &source[id.local_id()] {
Either::Left(ast::TypeOrConstParam::Type(id)) => {
ast::AnyHasAttrs::new(id.clone())
}
Either::Left(ast::TypeOrConstParam::Const(id)) => {
ast::AnyHasAttrs::new(id.clone())
}
Either::Right(id) => ast::AnyHasAttrs::new(id.clone()),
})
}
GenericParamId::TypeParamId(id) => {
id.parent.child_source(db).map(|source| match &source[id.local_id] {
Either::Left(id) => ast::AnyHasAttrs::new(id.clone()),
id.parent().child_source(db).map(|source| match &source[id.local_id()] {
Either::Left(ast::TypeOrConstParam::Type(id)) => {
ast::AnyHasAttrs::new(id.clone())
}
Either::Left(ast::TypeOrConstParam::Const(id)) => {
ast::AnyHasAttrs::new(id.clone())
}
Either::Right(id) => ast::AnyHasAttrs::new(id.clone()),
})
}
@ -464,10 +493,6 @@ impl AttrsWithOwner {
.parent
.child_source(db)
.map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
GenericParamId::ConstParamId(id) => id
.parent
.child_source(db)
.map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
},
AttrDefId::ExternBlockId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
};

View File

@ -9,9 +9,10 @@ use hir_expand::{
name::{AsName, Name},
ExpandResult, HirFileId, InFile,
};
use la_arena::{Arena, ArenaMap};
use la_arena::{Arena, ArenaMap, Idx};
use once_cell::unsync::Lazy;
use std::ops::DerefMut;
use stdx::impl_from;
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
use crate::{
@ -23,8 +24,8 @@ use crate::{
keys,
src::{HasChildSource, HasSource},
type_ref::{LifetimeRef, TypeBound, TypeRef},
AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalConstParamId,
LocalLifetimeParamId, LocalTypeParamId, Lookup, TypeParamId,
AdtId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId,
Lookup, TypeOrConstParamId,
};
/// Data about a generic type parameter (to a function, struct, impl, ...).
@ -55,12 +56,44 @@ pub enum TypeParamProvenance {
ArgumentImplTrait,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum TypeOrConstParamData {
TypeParamData(TypeParamData),
ConstParamData(ConstParamData),
}
impl TypeOrConstParamData {
pub fn name(&self) -> Option<&Name> {
match self {
TypeOrConstParamData::TypeParamData(x) => x.name.as_ref(),
TypeOrConstParamData::ConstParamData(x) => Some(&x.name),
}
}
pub fn type_param(&self) -> Option<&TypeParamData> {
match self {
TypeOrConstParamData::TypeParamData(x) => Some(&x),
TypeOrConstParamData::ConstParamData(_) => None,
}
}
pub fn is_trait_self(&self) -> bool {
match self {
TypeOrConstParamData::TypeParamData(x) => {
x.provenance == TypeParamProvenance::TraitSelf
}
TypeOrConstParamData::ConstParamData(_) => false,
}
}
}
impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
/// Data about the generic parameters of a function, struct, impl, etc.
#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
pub struct GenericParams {
pub types: Arena<TypeParamData>,
pub types: Arena<TypeOrConstParamData>,
pub lifetimes: Arena<LifetimeParamData>,
pub consts: Arena<ConstParamData>,
pub where_predicates: Vec<WherePredicate>,
}
@ -89,10 +122,18 @@ pub enum WherePredicate {
pub enum WherePredicateTypeTarget {
TypeRef(Interned<TypeRef>),
/// For desugared where predicates that can directly refer to a type param.
TypeParam(LocalTypeParamId),
TypeOrConstParam(LocalTypeOrConstParamId),
}
impl GenericParams {
// FIXME: almost every usecase of this function is wrong. every one should check
// const generics
pub fn type_iter<'a>(
&'a self,
) -> impl Iterator<Item = (Idx<TypeOrConstParamData>, &TypeParamData)> {
self.types.iter().filter_map(|x| x.1.type_param().map(|y| (x.0, y)))
}
pub(crate) fn generic_params_query(
db: &dyn DefDatabase,
def: GenericDefId,
@ -184,19 +225,32 @@ impl GenericParams {
}
fn fill_params(&mut self, lower_ctx: &LowerCtx, params: ast::GenericParamList) {
for type_param in params.type_params() {
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
// FIXME: Use `Path::from_src`
let default =
type_param.default_type().map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
let param = TypeParamData {
name: Some(name.clone()),
default,
provenance: TypeParamProvenance::TypeParamList,
};
self.types.alloc(param);
let type_ref = TypeRef::Path(name.into());
self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
for type_or_const_param in params.type_or_const_params() {
match type_or_const_param {
ast::TypeOrConstParam::Type(type_param) => {
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
// FIXME: Use `Path::from_src`
let default = type_param
.default_type()
.map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
let param = TypeParamData {
name: Some(name.clone()),
default,
provenance: TypeParamProvenance::TypeParamList,
};
self.types.alloc(param.into());
let type_ref = TypeRef::Path(name.into());
self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
}
ast::TypeOrConstParam::Const(const_param) => {
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
let ty = const_param
.ty()
.map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
let param = ConstParamData { name, ty: Interned::new(ty) };
self.types.alloc(param.into());
}
}
}
for lifetime_param in params.lifetime_params() {
let name =
@ -206,12 +260,6 @@ impl GenericParams {
let lifetime_ref = LifetimeRef::new_name(name);
self.fill_bounds(lower_ctx, &lifetime_param, Either::Right(lifetime_ref));
}
for const_param in params.const_params() {
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
let param = ConstParamData { name, ty: Interned::new(ty) };
self.consts.alloc(param);
}
}
fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) {
@ -287,10 +335,10 @@ impl GenericParams {
default: None,
provenance: TypeParamProvenance::ArgumentImplTrait,
};
let param_id = self.types.alloc(param);
let param_id = self.types.alloc(param.into());
for bound in bounds {
self.where_predicates.push(WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeParam(param_id),
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
bound: bound.clone(),
});
}
@ -311,27 +359,33 @@ impl GenericParams {
}
pub(crate) fn shrink_to_fit(&mut self) {
let Self { consts, lifetimes, types, where_predicates } = self;
consts.shrink_to_fit();
let Self { lifetimes, types, where_predicates } = self;
lifetimes.shrink_to_fit();
types.shrink_to_fit();
where_predicates.shrink_to_fit();
}
pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> {
self.types
.iter()
.find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None })
.filter(|x| matches!(x.1, TypeOrConstParamData::TypeParamData(_)))
.find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None })
}
pub fn find_const_by_name(&self, name: &Name) -> Option<LocalConstParamId> {
self.consts.iter().find_map(|(id, p)| if p.name == *name { Some(id) } else { None })
pub fn find_type_or_const_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> {
self.types
.iter()
.find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None })
}
pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> {
pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
self.types.iter().find_map(|(id, p)| {
if p.provenance == TypeParamProvenance::TraitSelf {
Some(id)
if let TypeOrConstParamData::TypeParamData(p) = p {
if p.provenance == TypeParamProvenance::TraitSelf {
Some(id)
} else {
None
}
} else {
None
}
@ -377,12 +431,12 @@ fn file_id_and_params_of(
}
}
impl HasChildSource<LocalTypeParamId> for GenericDefId {
type Value = Either<ast::TypeParam, ast::Trait>;
impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId {
type Value = Either<ast::TypeOrConstParam, ast::Trait>;
fn child_source(
&self,
db: &dyn DefDatabase,
) -> InFile<ArenaMap<LocalTypeParamId, Self::Value>> {
) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> {
let generic_params = db.generic_params(*self);
let mut idx_iter = generic_params.types.iter().map(|(idx, _)| idx);
@ -398,7 +452,7 @@ impl HasChildSource<LocalTypeParamId> for GenericDefId {
}
if let Some(generic_params_list) = generic_params_list {
for (idx, ast_param) in idx_iter.zip(generic_params_list.type_params()) {
for (idx, ast_param) in idx_iter.zip(generic_params_list.type_or_const_params()) {
params.insert(idx, Either::Left(ast_param));
}
}
@ -430,29 +484,6 @@ impl HasChildSource<LocalLifetimeParamId> for GenericDefId {
}
}
impl HasChildSource<LocalConstParamId> for GenericDefId {
type Value = ast::ConstParam;
fn child_source(
&self,
db: &dyn DefDatabase,
) -> InFile<ArenaMap<LocalConstParamId, Self::Value>> {
let generic_params = db.generic_params(*self);
let idx_iter = generic_params.consts.iter().map(|(idx, _)| idx);
let (file_id, generic_params_list) = file_id_and_params_of(*self, db);
let mut params = ArenaMap::default();
if let Some(generic_params_list) = generic_params_list {
for (idx, ast_param) in idx_iter.zip(generic_params_list.const_params()) {
params.insert(idx, ast_param);
}
}
InFile::new(file_id, params)
}
}
impl ChildBySource for GenericDefId {
fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
let (gfile_id, generic_params_list) = file_id_and_params_of(*self, db);
@ -461,28 +492,28 @@ impl ChildBySource for GenericDefId {
}
let generic_params = db.generic_params(*self);
let mut types_idx_iter = generic_params.types.iter().map(|(idx, _)| idx);
let mut toc_idx_iter = generic_params.types.iter().map(|(idx, _)| idx);
let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
let consts_idx_iter = generic_params.consts.iter().map(|(idx, _)| idx);
// For traits the first type index is `Self`, skip it.
if let GenericDefId::TraitId(_) = *self {
types_idx_iter.next().unwrap(); // advance_by(1);
toc_idx_iter.next().unwrap(); // advance_by(1);
}
if let Some(generic_params_list) = generic_params_list {
for (local_id, ast_param) in types_idx_iter.zip(generic_params_list.type_params()) {
let id = TypeParamId { parent: *self, local_id };
res[keys::TYPE_PARAM].insert(ast_param, id);
for (local_id, ast_param) in
toc_idx_iter.zip(generic_params_list.type_or_const_params())
{
let id = TypeOrConstParamId { parent: *self, local_id };
match ast_param {
ast::TypeOrConstParam::Type(a) => res[keys::TYPE_PARAM].insert(a, id),
ast::TypeOrConstParam::Const(a) => res[keys::CONST_PARAM].insert(a, id),
}
}
for (local_id, ast_param) in lts_idx_iter.zip(generic_params_list.lifetime_params()) {
let id = LifetimeParamId { parent: *self, local_id };
res[keys::LIFETIME_PARAM].insert(ast_param, id);
}
for (local_id, ast_param) in consts_idx_iter.zip(generic_params_list.const_params()) {
let id = ConstParamId { parent: *self, local_id };
res[keys::CONST_PARAM].insert(ast_param, id);
}
}
}
}

View File

@ -582,11 +582,14 @@ impl<'a> Ctx<'a> {
}
GenericsOwner::Trait(trait_def) => {
// traits get the Self type as an implicit first type parameter
generics.types.alloc(TypeParamData {
name: Some(name![Self]),
default: None,
provenance: TypeParamProvenance::TraitSelf,
});
generics.types.alloc(
TypeParamData {
name: Some(name![Self]),
default: None,
provenance: TypeParamProvenance::TraitSelf,
}
.into(),
);
// add super traits as bounds on Self
// i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
let self_param = TypeRef::Path(name![Self].into());

View File

@ -6,7 +6,7 @@ use itertools::Itertools;
use crate::{
attr::RawAttrs,
generics::{WherePredicate, WherePredicateTypeTarget},
generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
path::GenericArg,
type_ref::TraitBoundModifier,
visibility::RawVisibility,
@ -626,7 +626,7 @@ impl<'a> Printer<'a> {
}
fn print_generic_params(&mut self, params: &GenericParams) {
if params.types.is_empty() && params.lifetimes.is_empty() && params.consts.is_empty() {
if params.types.is_empty() && params.lifetimes.is_empty() {
return;
}
@ -639,24 +639,22 @@ impl<'a> Printer<'a> {
first = false;
w!(self, "{}", lt.name);
}
for (idx, ty) in params.types.iter() {
for (idx, x) in params.types.iter() {
if !first {
w!(self, ", ");
}
first = false;
match &ty.name {
Some(name) => w!(self, "{}", name),
None => w!(self, "_anon_{}", idx.into_raw()),
match x {
TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
Some(name) => w!(self, "{}", name),
None => w!(self, "_anon_{}", idx.into_raw()),
},
TypeOrConstParamData::ConstParamData(konst) => {
w!(self, "const {}: ", konst.name);
self.print_type_ref(&konst.ty);
}
}
}
for (_, konst) in params.consts.iter() {
if !first {
w!(self, ", ");
}
first = false;
w!(self, "const {}: ", konst.name);
self.print_type_ref(&konst.ty);
}
w!(self, ">");
}
@ -702,10 +700,12 @@ impl<'a> Printer<'a> {
match target {
WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
WherePredicateTypeTarget::TypeParam(id) => match &params.types[*id].name {
Some(name) => w!(this, "{}", name),
None => w!(this, "_anon_{}", id.into_raw()),
},
WherePredicateTypeTarget::TypeOrConstParam(id) => {
match &params.types[*id].name() {
Some(name) => w!(this, "{}", name),
None => w!(this, "_anon_{}", id.into_raw()),
}
}
}
w!(this, ": ");
this.print_type_bounds(std::slice::from_ref(bound));

View File

@ -9,8 +9,8 @@ use syntax::{ast, AstNode, AstPtr};
use crate::{
attr::AttrId,
dyn_map::{DynMap, Policy},
ConstId, ConstParamId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId,
StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, StaticId,
StructId, TraitId, TypeAliasId, TypeOrConstParamId, UnionId,
};
pub type Key<K, V> = crate::dyn_map::Key<K, V, AstPtrPolicy<K, V>>;
@ -28,9 +28,9 @@ pub const ENUM: Key<ast::Enum, EnumId> = Key::new();
pub const VARIANT: Key<ast::Variant, EnumVariantId> = Key::new();
pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new();
pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new();
pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
pub const TYPE_PARAM: Key<ast::TypeParam, TypeOrConstParamId> = Key::new();
pub const CONST_PARAM: Key<ast::ConstParam, TypeOrConstParamId> = Key::new();
pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new();
pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new();
pub const MACRO: Key<ast::Macro, MacroDefId> = Key::new();
pub const ATTR_MACRO_CALL: Key<ast::Item, MacroCallId> = Key::new();

View File

@ -279,12 +279,60 @@ pub struct BlockLoc {
impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypeParamId {
pub struct TypeOrConstParamId {
pub parent: GenericDefId,
pub local_id: LocalTypeParamId,
pub local_id: LocalTypeOrConstParamId,
}
pub type LocalTypeParamId = Idx<generics::TypeParamData>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// A TypeOrConstParamId with an invariant that it actually belongs to a type
pub struct TypeParamId(TypeOrConstParamId);
impl TypeParamId {
pub fn parent(&self) -> GenericDefId {
self.0.parent
}
pub fn local_id(&self) -> LocalTypeOrConstParamId {
self.0.local_id
}
}
impl From<TypeOrConstParamId> for TypeParamId {
fn from(x: TypeOrConstParamId) -> Self {
Self(x)
}
}
impl From<TypeParamId> for TypeOrConstParamId {
fn from(x: TypeParamId) -> Self {
x.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// A TypeOrConstParamId with an invariant that it actually belongs to a const
pub struct ConstParamId(TypeOrConstParamId);
impl ConstParamId {
pub fn parent(&self) -> GenericDefId {
self.0.parent
}
pub fn local_id(&self) -> LocalTypeOrConstParamId {
self.0.local_id
}
}
impl From<TypeOrConstParamId> for ConstParamId {
fn from(x: TypeOrConstParamId) -> Self {
Self(x)
}
}
impl From<ConstParamId> for TypeOrConstParamId {
fn from(x: ConstParamId) -> Self {
x.0
}
}
pub type LocalTypeOrConstParamId = Idx<generics::TypeOrConstParamData>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LifetimeParamId {
@ -293,13 +341,6 @@ pub struct LifetimeParamId {
}
pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ConstParamId {
pub parent: GenericDefId,
pub local_id: LocalConstParamId,
}
pub type LocalConstParamId = Idx<generics::ConstParamData>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ItemContainerId {
ExternBlockId(ExternBlockId),
@ -322,8 +363,8 @@ impl_from!(StructId, UnionId, EnumId for AdtId);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum GenericParamId {
TypeParamId(TypeParamId),
LifetimeParamId(LifetimeParamId),
ConstParamId(ConstParamId),
LifetimeParamId(LifetimeParamId),
}
impl_from!(TypeParamId, LifetimeParamId, ConstParamId for GenericParamId);
@ -632,9 +673,9 @@ impl AttrDefId {
AttrDefId::ExternBlockId(it) => it.lookup(db).container.krate,
AttrDefId::GenericParamId(it) => {
match it {
GenericParamId::TypeParamId(it) => it.parent,
GenericParamId::TypeParamId(it) => it.parent(),
GenericParamId::ConstParamId(it) => it.parent(),
GenericParamId::LifetimeParamId(it) => it.parent,
GenericParamId::ConstParamId(it) => it.parent,
}
.module(db)
.krate

View File

@ -15,7 +15,7 @@ use crate::{
builtin_type::BuiltinType,
db::DefDatabase,
expr::{ExprId, LabelId, PatId},
generics::GenericParams,
generics::{GenericParams, TypeOrConstParamData},
intern::Interned,
item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
nameres::DefMap,
@ -25,7 +25,7 @@ use crate::{
AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
TypeParamId, VariantId,
TypeOrConstParamId, TypeParamId, VariantId,
};
#[derive(Debug, Clone, Default)]
@ -195,7 +195,9 @@ impl Resolver {
if let Some(local_id) = params.find_type_by_name(first_name) {
let idx = if path.segments().len() == 1 { None } else { Some(1) };
return Some((
TypeNs::GenericParam(TypeParamId { local_id, parent: *def }),
TypeNs::GenericParam(
TypeOrConstParamId { local_id, parent: *def }.into(),
),
idx,
));
}
@ -285,14 +287,18 @@ impl Resolver {
Scope::ExprScope(_) => continue,
Scope::GenericParams { params, def } if n_segments > 1 => {
if let Some(local_id) = params.find_type_by_name(first_name) {
let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def });
if let Some(local_id) = params.find_type_or_const_by_name(first_name) {
let ty = TypeNs::GenericParam(
TypeOrConstParamId { local_id, parent: *def }.into(),
);
return Some(ResolveValueResult::Partial(ty, 1));
}
}
Scope::GenericParams { params, def } if n_segments == 1 => {
if let Some(local_id) = params.find_const_by_name(first_name) {
let val = ValueNs::GenericParam(ConstParamId { local_id, parent: *def });
if let Some(local_id) = params.find_type_or_const_by_name(first_name) {
let val = ValueNs::GenericParam(
TypeOrConstParamId { local_id, parent: *def }.into(),
);
return Some(ResolveValueResult::ValueNs(val));
}
}
@ -521,15 +527,22 @@ impl Scope {
Scope::GenericParams { params, def: parent } => {
let parent = *parent;
for (local_id, param) in params.types.iter() {
if let Some(name) = &param.name {
let id = TypeParamId { parent, local_id };
acc.add(name, ScopeDef::GenericParam(id.into()))
if let Some(name) = &param.name() {
let id = TypeOrConstParamId { parent, local_id };
let data = &db.generic_params(parent).types[local_id];
acc.add(
name,
ScopeDef::GenericParam(match data {
TypeOrConstParamData::TypeParamData(_) => {
GenericParamId::TypeParamId(id.into())
}
TypeOrConstParamData::ConstParamData(_) => {
GenericParamId::ConstParamId(id.into())
}
}),
);
}
}
for (local_id, param) in params.consts.iter() {
let id = ConstParamId { parent, local_id };
acc.add(&param.name, ScopeDef::GenericParam(id.into()))
}
for (local_id, param) in params.lifetimes.iter() {
let id = LifetimeParamId { parent, local_id };
acc.add(&param.name, ScopeDef::GenericParam(id.into()))

View File

@ -71,7 +71,7 @@ pub fn find_builtin_derive(
struct BasicAdtInfo {
name: tt::Ident,
type_params: usize,
type_or_const_params: usize,
}
fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
@ -104,8 +104,9 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
.token_by_range(name.syntax().text_range())
.unwrap_or_else(|| TokenId::unspecified());
let name_token = tt::Ident { id: name_token_id, text: name.text().into() };
let type_params = params.map_or(0, |type_param_list| type_param_list.type_params().count());
Ok(BasicAdtInfo { name: name_token, type_params })
let type_or_const_params =
params.map_or(0, |type_param_list| type_param_list.type_or_const_params().count());
Ok(BasicAdtInfo { name: name_token, type_or_const_params })
}
fn make_type_args(n: usize, bound: Vec<tt::TokenTree>) -> Vec<tt::TokenTree> {
@ -157,8 +158,8 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu
let name = info.name;
let trait_path_clone = trait_path.token_trees.clone();
let bound = (quote! { : ##trait_path_clone }).token_trees;
let type_params = make_type_args(info.type_params, bound);
let type_args = make_type_args(info.type_params, Vec::new());
let type_params = make_type_args(info.type_or_const_params, bound);
let type_args = make_type_args(info.type_or_const_params, Vec::new());
let trait_path = trait_path.token_trees;
let expanded = quote! {
impl ##type_params ##trait_path for #name ##type_args {}

View File

@ -3,6 +3,7 @@
use chalk_ir::{FloatTy, IntTy, Mutability, Scalar, UintTy};
use hir_def::{
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint},
generics::TypeOrConstParamData,
type_ref::Rawness,
FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
};
@ -237,27 +238,30 @@ impl TyExt for Ty {
let id = from_placeholder_idx(db, *idx);
let generic_params = db.generic_params(id.parent);
let param_data = &generic_params.types[id.local_id];
match param_data.provenance {
hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
let substs = TyBuilder::type_params_subst(db, id.parent);
let predicates = db
.generic_predicates(id.parent)
.iter()
.map(|pred| pred.clone().substitute(Interner, &substs))
.filter(|wc| match &wc.skip_binders() {
WhereClause::Implemented(tr) => {
&tr.self_type_parameter(Interner) == self
}
WhereClause::AliasEq(AliasEq {
alias: AliasTy::Projection(proj),
ty: _,
}) => &proj.self_type_parameter(Interner) == self,
_ => false,
})
.collect::<Vec<_>>();
match param_data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
let substs = TyBuilder::type_params_subst(db, id.parent);
let predicates = db
.generic_predicates(id.parent)
.iter()
.map(|pred| pred.clone().substitute(Interner, &substs))
.filter(|wc| match &wc.skip_binders() {
WhereClause::Implemented(tr) => {
&tr.self_type_parameter(Interner) == self
}
WhereClause::AliasEq(AliasEq {
alias: AliasTy::Projection(proj),
ty: _,
}) => &proj.self_type_parameter(Interner) == self,
_ => false,
})
.collect::<Vec<_>>();
Some(predicates)
}
Some(predicates)
}
_ => None,
},
_ => None,
}
}

View File

@ -6,7 +6,7 @@ use std::sync::Arc;
use base_db::{impl_intern_key, salsa, CrateId, Upcast};
use hir_def::{
db::DefDatabase, expr::ExprId, BlockId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId,
ImplId, LifetimeParamId, LocalFieldId, TypeParamId, VariantId,
ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
};
use la_arena::ArenaMap;
@ -61,7 +61,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn generic_predicates_for_param(
&self,
def: GenericDefId,
param_id: TypeParamId,
param_id: TypeOrConstParamId,
assoc_name: Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]>;
@ -94,12 +94,13 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::interned]
fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId;
#[salsa::interned]
fn intern_type_param_id(&self, param_id: TypeParamId) -> InternedTypeParamId;
fn intern_type_or_const_param_id(
&self,
param_id: TypeOrConstParamId,
) -> InternedTypeOrConstParamId;
#[salsa::interned]
fn intern_lifetime_param_id(&self, param_id: LifetimeParamId) -> InternedLifetimeParamId;
#[salsa::interned]
fn intern_const_param_id(&self, param_id: ConstParamId) -> InternedConstParamId;
#[salsa::interned]
fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
#[salsa::interned]
fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
@ -186,8 +187,8 @@ fn hir_database_is_object_safe() {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InternedTypeParamId(salsa::InternId);
impl_intern_key!(InternedTypeParamId);
pub struct InternedTypeOrConstParamId(salsa::InternId);
impl_intern_key!(InternedTypeOrConstParamId);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InternedLifetimeParamId(salsa::InternId);

View File

@ -10,7 +10,7 @@ use hir_def::{
body,
db::DefDatabase,
find_path,
generics::TypeParamProvenance,
generics::{TypeOrConstParamData, TypeParamProvenance},
intern::{Internable, Interned},
item_scope::ItemInNs,
path::{Path, PathKind},
@ -23,7 +23,6 @@ use itertools::Itertools;
use syntax::SmolStr;
use crate::{
const_from_placeholder_idx,
db::HirDatabase,
from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
mapping::from_chalk,
@ -319,10 +318,10 @@ impl HirDisplay for Const {
ConstValue::BoundVar(idx) => idx.hir_fmt(f),
ConstValue::InferenceVar(..) => write!(f, "_"),
ConstValue::Placeholder(idx) => {
let id = const_from_placeholder_idx(f.db, idx);
let id = from_placeholder_idx(f.db, idx);
let generics = generics(f.db.upcast(), id.parent);
let param_data = &generics.params.consts[id.local_id];
write!(f, "{}", param_data.name)
let param_data = &generics.params.types[id.local_id];
write!(f, "{}", param_data.name().unwrap())
}
ConstValue::Concrete(c) => write!(f, "{}", c.interned),
}
@ -682,34 +681,39 @@ impl HirDisplay for Ty {
let id = from_placeholder_idx(f.db, *idx);
let generics = generics(f.db.upcast(), id.parent);
let param_data = &generics.params.types[id.local_id];
match param_data.provenance {
TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
}
TypeParamProvenance::ArgumentImplTrait => {
let substs = generics.type_params_subst(f.db);
let bounds =
f.db.generic_predicates(id.parent)
.iter()
.map(|pred| pred.clone().substitute(Interner, &substs))
.filter(|wc| match &wc.skip_binders() {
WhereClause::Implemented(tr) => {
&tr.self_type_parameter(Interner) == self
}
WhereClause::AliasEq(AliasEq {
alias: AliasTy::Projection(proj),
ty: _,
}) => &proj.self_type_parameter(Interner) == self,
_ => false,
})
.collect::<Vec<_>>();
let krate = id.parent.module(f.db.upcast()).krate();
write_bounds_like_dyn_trait_with_prefix(
"impl",
&bounds,
SizedByDefault::Sized { anchor: krate },
f,
)?;
match param_data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))?
}
TypeParamProvenance::ArgumentImplTrait => {
let substs = generics.type_params_subst(f.db);
let bounds =
f.db.generic_predicates(id.parent)
.iter()
.map(|pred| pred.clone().substitute(Interner, &substs))
.filter(|wc| match &wc.skip_binders() {
WhereClause::Implemented(tr) => {
&tr.self_type_parameter(Interner) == self
}
WhereClause::AliasEq(AliasEq {
alias: AliasTy::Projection(proj),
ty: _,
}) => &proj.self_type_parameter(Interner) == self,
_ => false,
})
.collect::<Vec<_>>();
let krate = id.parent.module(f.db.upcast()).krate();
write_bounds_like_dyn_trait_with_prefix(
"impl",
&bounds,
SizedByDefault::Sized { anchor: krate },
f,
)?;
}
},
TypeOrConstParamData::ConstParamData(p) => {
write!(f, "{}", p.name)?;
}
}
}

View File

@ -10,6 +10,7 @@ use std::{
use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
use hir_def::{
expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp},
generics::TypeOrConstParamData,
path::{GenericArg, GenericArgs},
resolver::resolver_for_expr,
FieldId, FunctionId, ItemContainerId, Lookup,
@ -1037,8 +1038,15 @@ impl<'a> InferenceContext<'a> {
let total_len = parent_params + type_params + impl_trait_params;
let mut substs = Vec::with_capacity(total_len);
// Parent arguments are unknown
for _ in def_generics.iter_parent() {
substs.push(self.table.new_type_var());
for (_id, param) in def_generics.iter_parent() {
match param {
TypeOrConstParamData::TypeParamData(_) => {
substs.push(self.table.new_type_var());
}
TypeOrConstParamData::ConstParamData(_) => {
// FIXME: here we should do something
}
}
}
// handle provided type arguments
if let Some(generic_args) = generic_args {

View File

@ -40,7 +40,7 @@ use chalk_ir::{
use hir_def::{
expr::ExprId,
type_ref::{ConstScalar, Rawness},
TypeParamId,
TypeOrConstParamId,
};
use crate::{db::HirDatabase, utils::generics};
@ -55,9 +55,9 @@ pub use lower::{
TyDefId, TyLoweringContext, ValueTyDefId,
};
pub use mapping::{
const_from_placeholder_idx, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
from_placeholder_idx, lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
to_foreign_def_id, to_placeholder_idx,
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id,
to_placeholder_idx,
};
pub use traits::TraitEnvironment;
pub use utils::all_super_traits;
@ -129,7 +129,7 @@ pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
}
/// Return an index of a parameter in the generic type parameter list by it's id.
pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
generics(db.upcast(), id.parent).param_idx(id)
}

View File

@ -10,6 +10,7 @@ use std::{iter, sync::Arc};
use base_db::CrateId;
use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
use hir_def::generics::TypeOrConstParamData;
use hir_def::intern::Interned;
use hir_def::{
adt::StructKind,
@ -19,15 +20,16 @@ use hir_def::{
path::{GenericArg, Path, PathSegment, PathSegments},
resolver::{HasResolver, Resolver, TypeNs},
type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
TypeAliasId, TypeParamId, UnionId, VariantId,
AdtId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule,
ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId,
UnionId, VariantId,
};
use hir_def::{ConstParamId, TypeOrConstParamId};
use hir_expand::{name::Name, ExpandResult};
use la_arena::ArenaMap;
use rustc_hash::FxHashSet;
use smallvec::SmallVec;
use stdx::impl_from;
use stdx::{impl_from, never};
use syntax::{ast, SmolStr};
use crate::all_super_traits;
@ -267,7 +269,7 @@ impl<'a> TyLoweringContext<'a> {
if let Some(def) = self.resolver.generic_def() {
let generics = generics(self.db.upcast(), def);
let param = generics
.iter()
.type_iter()
.filter(|(_, data)| {
data.provenance == TypeParamProvenance::ArgumentImplTrait
})
@ -353,7 +355,7 @@ impl<'a> TyLoweringContext<'a> {
/// This is only for `generic_predicates_for_param`, where we can't just
/// lower the self types of the predicates since that could lead to cycles.
/// So we just check here if the `type_ref` resolves to a generic param, and which.
fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeParamId> {
fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeOrConstParamId> {
let path = match type_ref {
TypeRef::Path(path) => path,
_ => return None,
@ -370,7 +372,7 @@ impl<'a> TyLoweringContext<'a> {
_ => return None,
};
match resolution {
TypeNs::GenericParam(param_id) => Some(param_id),
TypeNs::GenericParam(param_id) => Some(param_id.into()),
_ => None,
}
}
@ -469,10 +471,10 @@ impl<'a> TyLoweringContext<'a> {
);
match self.type_param_mode {
TypeParamLoweringMode::Placeholder => {
TyKind::Placeholder(to_placeholder_idx(self.db, param_id))
TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
}
TypeParamLoweringMode::Variable => {
let idx = generics.param_idx(param_id).expect("matching generics");
let idx = generics.param_idx(param_id.into()).expect("matching generics");
TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
}
}
@ -758,11 +760,13 @@ impl<'a> TyLoweringContext<'a> {
| WherePredicate::TypeBound { target, bound } => {
let self_ty = match target {
WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
WherePredicateTypeTarget::TypeParam(param_id) => {
WherePredicateTypeTarget::TypeOrConstParam(param_id) => {
let generic_def = self.resolver.generic_def().expect("generics in scope");
let generics = generics(self.db.upcast(), generic_def);
let param_id =
hir_def::TypeParamId { parent: generic_def, local_id: *param_id };
let param_id = hir_def::TypeOrConstParamId {
parent: generic_def,
local_id: *param_id,
};
let placeholder = to_placeholder_idx(self.db, param_id);
match self.type_param_mode {
TypeParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder),
@ -973,7 +977,7 @@ fn named_associated_type_shorthand_candidates<R>(
db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
),
TypeNs::GenericParam(param_id) => {
let predicates = db.generic_predicates_for_param(def, param_id, assoc_name);
let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
// FIXME: how to correctly handle higher-ranked bounds here?
WhereClause::Implemented(tr) => search(
@ -987,11 +991,9 @@ fn named_associated_type_shorthand_candidates<R>(
return res;
}
// Handle `Self::Type` referring to own associated type in trait definitions
if let GenericDefId::TraitId(trait_id) = param_id.parent {
if let GenericDefId::TraitId(trait_id) = param_id.parent() {
let generics = generics(db.upcast(), trait_id.into());
if generics.params.types[param_id.local_id].provenance
== TypeParamProvenance::TraitSelf
{
if generics.params.types[param_id.local_id()].is_trait_self() {
let trait_ref = TyBuilder::trait_ref(db, trait_id)
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
.build();
@ -1036,7 +1038,7 @@ pub(crate) fn field_types_query(
pub(crate) fn generic_predicates_for_param_query(
db: &dyn HirDatabase,
def: GenericDefId,
param_id: TypeParamId,
param_id: TypeOrConstParamId,
assoc_name: Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]> {
let resolver = def.resolver(db.upcast());
@ -1051,11 +1053,11 @@ pub(crate) fn generic_predicates_for_param_query(
| WherePredicate::TypeBound { target, bound, .. } => {
match target {
WherePredicateTypeTarget::TypeRef(type_ref) => {
if ctx.lower_ty_only_param(type_ref) != Some(param_id) {
if ctx.lower_ty_only_param(type_ref) != Some(param_id.into()) {
return false;
}
}
WherePredicateTypeTarget::TypeParam(local_id) => {
WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
if *local_id != param_id.local_id {
return false;
}
@ -1105,7 +1107,7 @@ pub(crate) fn generic_predicates_for_param_recover(
_db: &dyn HirDatabase,
_cycle: &[String],
_def: &GenericDefId,
_param_id: &TypeParamId,
_param_id: &TypeOrConstParamId,
_assoc_name: &Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]> {
Arc::new([])
@ -1233,7 +1235,7 @@ pub(crate) fn generic_defaults_query(
let generic_params = generics(db.upcast(), def);
let defaults = generic_params
.iter()
.type_iter()
.enumerate()
.map(|(idx, (_, p))| {
let mut ty =
@ -1267,7 +1269,7 @@ pub(crate) fn generic_defaults_recover(
// we still need one default per parameter
let defaults = generic_params
.iter()
.type_iter()
.enumerate()
.map(|(idx, _)| {
let ty = TyKind::Error.intern(Interner);
@ -1497,13 +1499,19 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
make_binders(&generics, ctx.lower_ty(&impl_data.self_ty))
}
// returns None if def is a type arg
pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
let parent_data = db.generic_params(def.parent);
let data = &parent_data.consts[def.local_id];
let resolver = def.parent.resolver(db.upcast());
let parent_data = db.generic_params(def.parent());
let data = &parent_data.types[def.local_id()];
let resolver = def.parent().resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver);
ctx.lower_ty(&data.ty)
match data {
TypeOrConstParamData::TypeParamData(_) => {
never!();
Ty::new(Interner, TyKind::Error)
}
TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(&d.ty),
}
}
pub(crate) fn impl_self_ty_recover(

View File

@ -6,7 +6,7 @@
use chalk_solve::rust_ir;
use base_db::salsa::{self, InternKey};
use hir_def::{ConstParamId, LifetimeParamId, TraitId, TypeAliasId, TypeParamId};
use hir_def::{LifetimeParamId, TraitId, TypeAliasId, TypeOrConstParamId};
use crate::{
chalk_db, db::HirDatabase, AssocTypeId, CallableDefId, ChalkTraitId, FnDefId, ForeignDefId,
@ -119,14 +119,14 @@ pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId {
salsa::InternKey::from_intern_id(id.0)
}
pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeParamId {
pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeOrConstParamId {
assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
db.lookup_intern_type_param_id(interned_id)
db.lookup_intern_type_or_const_param_id(interned_id)
}
pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeParamId) -> PlaceholderIndex {
let interned_id = db.intern_type_param_id(id);
pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> PlaceholderIndex {
let interned_id = db.intern_type_or_const_param_id(id);
PlaceholderIndex {
ui: chalk_ir::UniverseIndex::ROOT,
idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(),
@ -139,12 +139,6 @@ pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> L
db.lookup_intern_lifetime_param_id(interned_id)
}
pub fn const_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> ConstParamId {
assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
db.lookup_intern_const_param_id(interned_id)
}
pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id))
}

View File

@ -8,13 +8,14 @@ use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
use hir_def::{
db::DefDatabase,
generics::{
GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
GenericParams, TypeOrConstParamData, TypeParamData, TypeParamProvenance, WherePredicate,
WherePredicateTypeTarget,
},
intern::Interned,
path::Path,
resolver::{HasResolver, TypeNs},
type_ref::{TraitBoundModifier, TypeRef},
GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeParamId,
GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
};
use hir_expand::name::{name, Name};
use rustc_hash::FxHashSet;
@ -55,7 +56,9 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[Trait
TypeRef::Path(p) if p == &Path::from(name![Self]) => bound.as_path(),
_ => None,
},
WherePredicateTypeTarget::TypeParam(local_id) if Some(*local_id) == trait_self => {
WherePredicateTypeTarget::TypeOrConstParam(local_id)
if Some(*local_id) == trait_self =>
{
bound.as_path()
}
_ => None,
@ -80,7 +83,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
// SmallVec if performance is a concern)
let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
let trait_self = match generic_params.find_trait_self_param() {
Some(p) => TypeParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
None => return Vec::new(),
};
db.generic_predicates_for_param(trait_self.parent, trait_self, None)
@ -181,34 +184,33 @@ pub(crate) struct Generics {
}
impl Generics {
pub(crate) fn iter<'a>(
// FIXME: we should drop this and handle const and type generics at the same time
pub(crate) fn type_iter<'a>(
&'a self,
) -> impl Iterator<Item = (TypeParamId, &'a TypeParamData)> + 'a {
) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeParamData)> + 'a {
self.parent_generics
.as_ref()
.into_iter()
.flat_map(|it| {
it.params
.types
.iter()
.map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p))
.type_iter()
.map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
})
.chain(
self.params
.types
.iter()
.map(move |(local_id, p)| (TypeParamId { parent: self.def, local_id }, p)),
self.params.type_iter().map(move |(local_id, p)| {
(TypeOrConstParamId { parent: self.def, local_id }, p)
}),
)
}
pub(crate) fn iter_parent<'a>(
&'a self,
) -> impl Iterator<Item = (TypeParamId, &'a TypeParamData)> + 'a {
) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
self.parent_generics.as_ref().into_iter().flat_map(|it| {
it.params
.types
.iter()
.map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p))
.map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
})
}
@ -219,7 +221,8 @@ impl Generics {
/// (total, parents, child)
pub(crate) fn len_split(&self) -> (usize, usize, usize) {
let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
let child = self.params.types.len();
// FIXME: we should not filter const generics here, but at now it breaks tests
let child = self.params.types.iter().filter_map(|x| x.1.type_param()).count();
(parent + child, parent, child)
}
@ -230,28 +233,31 @@ impl Generics {
.params
.types
.iter()
.filter(|(_, p)| p.provenance == TypeParamProvenance::TraitSelf)
.filter_map(|x| x.1.type_param())
.filter(|p| p.provenance == TypeParamProvenance::TraitSelf)
.count();
let list_params = self
.params
.types
.iter()
.filter(|(_, p)| p.provenance == TypeParamProvenance::TypeParamList)
.filter_map(|x| x.1.type_param())
.filter(|p| p.provenance == TypeParamProvenance::TypeParamList)
.count();
let impl_trait_params = self
.params
.types
.iter()
.filter(|(_, p)| p.provenance == TypeParamProvenance::ArgumentImplTrait)
.filter_map(|x| x.1.type_param())
.filter(|p| p.provenance == TypeParamProvenance::ArgumentImplTrait)
.count();
(parent, self_params, list_params, impl_trait_params)
}
pub(crate) fn param_idx(&self, param: TypeParamId) -> Option<usize> {
pub(crate) fn param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
Some(self.find_param(param)?.0)
}
fn find_param(&self, param: TypeParamId) -> Option<(usize, &TypeParamData)> {
fn find_param(&self, param: TypeOrConstParamId) -> Option<(usize, &TypeOrConstParamData)> {
if param.parent == self.def {
let (idx, (_local_id, data)) = self
.params
@ -271,7 +277,7 @@ impl Generics {
pub(crate) fn bound_vars_subst(&self, debruijn: DebruijnIndex) -> Substitution {
Substitution::from_iter(
Interner,
self.iter()
self.type_iter()
.enumerate()
.map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)),
)
@ -281,7 +287,7 @@ impl Generics {
pub(crate) fn type_params_subst(&self, db: &dyn HirDatabase) -> Substitution {
Substitution::from_iter(
Interner,
self.iter().map(|(id, _)| {
self.type_iter().map(|(id, _)| {
TyKind::Placeholder(crate::to_placeholder_idx(db, id)).intern(Interner)
}),
)

View File

@ -2913,6 +2913,27 @@ fn main() {
);
}
#[test]
fn const_generic_order() {
check(
r#"
struct Foo;
struct S$0T<const C: usize = 1, T = Foo>(T);
"#,
expect![[r#"
*ST*
```rust
test
```
```rust
struct ST<const C: usize, T = Foo>
```
"#]],
);
}
#[test]
fn hover_self_param_shows_type() {
check(

View File

@ -12,6 +12,7 @@ use ide_db::{
SymbolKind,
};
use ide_db::{defs::Definition, RootDatabase};
use stdx::never;
use syntax::{
ast::{self, HasName},
match_ast, AstNode, SmolStr, SyntaxNode, TextRange,
@ -435,9 +436,18 @@ impl ToNav for hir::Label {
impl TryToNav for hir::TypeParam {
fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let InFile { file_id, value } = self.source(db)?;
let InFile { file_id, value } = self.merge().source(db)?;
let name = self.name(db).to_smol_str();
let value = match value {
Either::Left(ast::TypeOrConstParam::Type(x)) => Either::Left(x),
Either::Left(ast::TypeOrConstParam::Const(_)) => {
never!();
return None;
}
Either::Right(x) => Either::Right(x),
};
let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db);
let focus_range = |syntax: &_| InFile::new(file_id, syntax).original_file_range_opt(db);
let FileRange { file_id, range: full_range } = match &value {
@ -464,6 +474,12 @@ impl TryToNav for hir::TypeParam {
}
}
impl TryToNav for hir::TypeOrConstParam {
fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
self.split(db).try_to_nav(db)
}
}
impl TryToNav for hir::LifetimeParam {
fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let InFile { file_id, value } = self.source(db)?;
@ -486,9 +502,17 @@ impl TryToNav for hir::LifetimeParam {
impl TryToNav for hir::ConstParam {
fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let InFile { file_id, value } = self.source(db)?;
let InFile { file_id, value } = self.merge().source(db)?;
let name = self.name(db).to_smol_str();
let value = match value {
Either::Left(ast::TypeOrConstParam::Const(x)) => x,
_ => {
never!();
return None;
}
};
let focus_range = value.name().and_then(|it| orig_focus_range(db, file_id, it.syntax()));
let FileRange { file_id, range: full_range } =
InFile::new(file_id, value.syntax()).original_file_range(db);

View File

@ -259,8 +259,8 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag {
Definition::Local(_) => SymbolKind::Local,
Definition::GenericParam(gp) => match gp {
hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
},
Definition::Label(_) => SymbolKind::Label,
Definition::BuiltinAttr(_) => SymbolKind::BuiltinAttr,

View File

@ -109,6 +109,13 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
<span class="comment documentation">/// ```</span>
<span class="comment documentation">///</span>
<span class="comment documentation">/// ```</span>
<span class="comment documentation">/// </span><span class="comment injected">// functions</span>
<span class="comment documentation">/// </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="angle injected">&lt;</span><span class="type_param declaration injected">T</span><span class="comma injected">,</span><span class="none injected"> </span><span class="keyword injected">const</span><span class="none injected"> </span><span class="const_param declaration injected">X</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">usize</span><span class="angle injected">&gt;</span><span class="parenthesis injected">(</span><span class="value_param declaration injected">arg</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">i32</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span>
<span class="comment documentation">/// </span><span class="none injected"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">x</span><span class="colon injected">:</span><span class="none injected"> </span><span class="type_param injected">T</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="const_param injected">X</span><span class="semicolon injected">;</span>
<span class="comment documentation">/// </span><span class="brace injected">}</span>
<span class="comment documentation">/// ```</span>
<span class="comment documentation">///</span>
<span class="comment documentation">/// ```sh</span>
<span class="comment documentation">/// echo 1</span>
<span class="comment documentation">/// ```</span>

View File

@ -599,6 +599,13 @@ impl Foo {
/// let foobar = Foo::new().bar();
/// ```
///
/// ```
/// // functions
/// fn foo<T, const X: usize>(arg: i32) {
/// let x: T = X;
/// }
/// ```
///
/// ```sh
/// echo 1
/// ```

View File

@ -85,21 +85,23 @@ fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code:
if let Some(generic_params) = &generic_params {
let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
let type_params = generic_params.type_params().map(|type_param| {
let mut buf = String::new();
if let Some(it) = type_param.name() {
format_to!(buf, "{}", it.syntax());
let toc_params = generic_params.type_or_const_params().map(|toc_param| match toc_param {
ast::TypeOrConstParam::Type(type_param) => {
let mut buf = String::new();
if let Some(it) = type_param.name() {
format_to!(buf, "{}", it.syntax());
}
if let Some(it) = type_param.colon_token() {
format_to!(buf, "{} ", it);
}
if let Some(it) = type_param.type_bound_list() {
format_to!(buf, "{}", it.syntax());
}
buf
}
if let Some(it) = type_param.colon_token() {
format_to!(buf, "{} ", it);
}
if let Some(it) = type_param.type_bound_list() {
format_to!(buf, "{}", it.syntax());
}
buf
ast::TypeOrConstParam::Const(const_param) => const_param.syntax().to_string(),
});
let const_params = generic_params.const_params().map(|t| t.syntax().to_string());
let generics = lifetimes.chain(type_params).chain(const_params).format(", ");
let generics = lifetimes.chain(toc_params).format(", ");
format_to!(buf, "<{}>", generics);
}

View File

@ -23,8 +23,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let type_param_list = ctx.find_node_at_offset::<ast::GenericParamList>()?;
let mut type_params = type_param_list.type_params();
if type_params.all(|p| p.type_bound_list().is_none()) {
let mut type_params = type_param_list.type_or_const_params();
if type_params.all(|p| match p {
ast::TypeOrConstParam::Type(t) => t.type_bound_list().is_none(),
ast::TypeOrConstParam::Const(_) => true,
}) {
return None;
}
@ -50,7 +53,11 @@ pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext
}
};
for type_param in type_param_list.type_params() {
for toc_param in type_param_list.type_or_const_params() {
let type_param = match toc_param {
ast::TypeOrConstParam::Type(x) => x,
ast::TypeOrConstParam::Const(_) => continue,
};
if let Some(tbl) = type_param.type_bound_list() {
if let Some(predicate) = build_predicate(type_param) {
where_clause.add_predicate(predicate)

View File

@ -435,7 +435,11 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
buf.push_str("impl");
if let Some(generic_params) = &generic_params {
let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
let type_params = generic_params.type_params().map(|type_param| {
let toc_params = generic_params.type_or_const_params().map(|toc_param| {
let type_param = match toc_param {
ast::TypeOrConstParam::Type(x) => x,
ast::TypeOrConstParam::Const(x) => return x.syntax().to_string(),
};
let mut buf = String::new();
if let Some(it) = type_param.name() {
format_to!(buf, "{}", it.syntax());
@ -448,8 +452,7 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
}
buf
});
let const_params = generic_params.const_params().map(|t| t.syntax().to_string());
let generics = lifetimes.chain(type_params).chain(const_params).format(", ");
let generics = lifetimes.chain(toc_params).format(", ");
format_to!(buf, "<{}>", generics);
}
buf.push(' ');
@ -463,15 +466,11 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
.lifetime_params()
.filter_map(|it| it.lifetime())
.map(|it| SmolStr::from(it.text()));
let type_params = generic_params
.type_params()
let toc_params = generic_params
.type_or_const_params()
.filter_map(|it| it.name())
.map(|it| SmolStr::from(it.text()));
let const_params = generic_params
.const_params()
.filter_map(|it| it.name())
.map(|it| SmolStr::from(it.text()));
format_to!(buf, "<{}>", lifetime_params.chain(type_params).chain(const_params).format(", "))
format_to!(buf, "<{}>", lifetime_params.chain(toc_params).format(", "))
}
match adt.where_clause() {

View File

@ -201,8 +201,8 @@ fn render_resolution_(
ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
}),
ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),

View File

@ -129,12 +129,12 @@ impl RootDatabase {
hir::db::FnDefDatumQuery
hir::db::ReturnTypeImplTraitsQuery
hir::db::InternCallableDefQuery
hir::db::InternTypeParamIdQuery
hir::db::InternTypeOrConstParamIdQuery
hir::db::InternImplTraitIdQuery
hir::db::InternClosureQuery
hir::db::AssociatedTyValueQuery
hir::db::TraitSolveQueryQuery
hir::db::InternTypeParamIdQuery
hir::db::InternTypeOrConstParamIdQuery
// SymbolsDatabase
crate::symbol_index::ModuleSymbolsQuery

View File

@ -482,9 +482,9 @@ impl From<PathResolution> for Definition {
}
PathResolution::Local(local) => Definition::Local(local),
PathResolution::TypeParam(par) => Definition::GenericParam(par.into()),
PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
PathResolution::Macro(def) => Definition::Macro(def),
PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
PathResolution::BuiltinAttr(attr) => Definition::BuiltinAttr(attr),
PathResolution::ToolModule(tool) => Definition::ToolModule(tool),
}

View File

@ -1,6 +1,7 @@
//! See [`PathTransform`].
use crate::helpers::mod_path_to_ast;
use either::Either;
use hir::{HirDisplay, SemanticsScope};
use rustc_hash::FxHashMap;
use syntax::{
@ -94,15 +95,20 @@ impl<'a> PathTransform<'a> {
// a default type. If they do, go for that type from `hir` to `ast` so
// the resulting change can be applied correctly.
.zip(self.substs.iter().map(Some).chain(std::iter::repeat(None)))
.filter_map(|(k, v)| match v {
Some(v) => Some((k, v.clone())),
None => {
let default = k.default(db)?;
Some((
k,
ast::make::ty(&default.display_source_code(db, source_module.into()).ok()?),
))
}
.filter_map(|(k, v)| match k.split(db) {
Either::Left(_) => None,
Either::Right(t) => match v {
Some(v) => Some((k, v.clone())),
None => {
let default = t.default(db)?;
Some((
k,
ast::make::ty(
&default.display_source_code(db, source_module.into()).ok()?,
),
))
}
},
})
.collect();
let res = Ctx { substs: substs_by_param, target_module, source_scope: self.source_scope };
@ -111,7 +117,7 @@ impl<'a> PathTransform<'a> {
}
struct Ctx<'a> {
substs: FxHashMap<hir::TypeParam, ast::Type>,
substs: FxHashMap<hir::TypeOrConstParam, ast::Type>,
target_module: hir::Module,
source_scope: &'a SemanticsScope<'a>,
}
@ -150,7 +156,7 @@ impl<'a> Ctx<'a> {
match resolution {
hir::PathResolution::TypeParam(tp) => {
if let Some(subst) = self.substs.get(&tp) {
if let Some(subst) = self.substs.get(&tp.merge()) {
let parent = path.syntax().parent()?;
if let Some(parent) = ast::Path::cast(parent.clone()) {
// Path inside path means that there is an associated

View File

@ -124,20 +124,23 @@ impl Definition {
src.with_value(name.syntax()).original_file_range_opt(sema.db)
}
Definition::GenericParam(generic_param) => match generic_param {
hir::GenericParam::TypeParam(type_param) => {
let src = type_param.source(sema.db)?;
hir::GenericParam::LifetimeParam(lifetime_param) => {
let src = lifetime_param.source(sema.db)?;
src.with_value(src.value.lifetime()?.syntax()).original_file_range_opt(sema.db)
}
_ => {
let x = match generic_param {
hir::GenericParam::TypeParam(it) => it.merge(),
hir::GenericParam::ConstParam(it) => it.merge(),
hir::GenericParam::LifetimeParam(_) => return None,
};
let src = x.source(sema.db)?;
let name = match &src.value {
Either::Left(type_param) => type_param.name()?,
Either::Right(_trait) => return None,
Either::Left(x) => x.name()?,
Either::Right(_) => return None,
};
src.with_value(name.syntax()).original_file_range_opt(sema.db)
}
hir::GenericParam::LifetimeParam(lifetime_param) => {
let src = lifetime_param.source(sema.db)?;
let lifetime = src.value.lifetime()?;
src.with_value(lifetime.syntax()).original_file_range_opt(sema.db)
}
hir::GenericParam::ConstParam(it) => name_range(it, sema),
},
Definition::Label(label) => {
let src = label.source(sema.db);

View File

@ -22,7 +22,7 @@ pub use self::{
generated::{nodes::*, tokens::*},
node_ext::{
AttrKind, FieldKind, Macro, NameLike, NameOrNameRef, PathSegmentKind, SelfParamKind,
SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind,
SlicePatComponents, StructKind, TypeBoundKind, TypeOrConstParam, VisibilityKind,
},
operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp},
token_ext::{CommentKind, CommentPlacement, CommentShape, IsString, QuoteOffsets, Radix},

View File

@ -638,6 +638,21 @@ impl ast::TypeBound {
}
}
#[derive(Debug, Clone)]
pub enum TypeOrConstParam {
Type(ast::TypeParam),
Const(ast::ConstParam),
}
impl TypeOrConstParam {
pub fn name(&self) -> Option<ast::Name> {
match self {
TypeOrConstParam::Type(x) => x.name(),
TypeOrConstParam::Const(x) => x.name(),
}
}
}
pub enum VisibilityKind {
In(ast::Path),
PubCrate,
@ -746,16 +761,11 @@ impl ast::GenericParamList {
ast::GenericParam::TypeParam(_) | ast::GenericParam::ConstParam(_) => None,
})
}
pub fn type_params(&self) -> impl Iterator<Item = ast::TypeParam> {
pub fn type_or_const_params(&self) -> impl Iterator<Item = ast::TypeOrConstParam> {
self.generic_params().filter_map(|param| match param {
ast::GenericParam::TypeParam(it) => Some(it),
ast::GenericParam::LifetimeParam(_) | ast::GenericParam::ConstParam(_) => None,
})
}
pub fn const_params(&self) -> impl Iterator<Item = ast::ConstParam> {
self.generic_params().filter_map(|param| match param {
ast::GenericParam::ConstParam(it) => Some(it),
ast::GenericParam::TypeParam(_) | ast::GenericParam::LifetimeParam(_) => None,
ast::GenericParam::TypeParam(it) => Some(ast::TypeOrConstParam::Type(it)),
ast::GenericParam::LifetimeParam(_) => None,
ast::GenericParam::ConstParam(it) => Some(ast::TypeOrConstParam::Const(it)),
})
}
}