Merge #1290
1290: Add Union to code_model r=matklad a=matklad @flodiebold I am conflicted about two possible implementation approaches: * we can add a separate `struct Union` to code model * we can add `fn is_union(&self)` to existing `Struct` This PR goes with the former approach, because it seems like Unions are sufficiently different in semantics to warrant a separate types. Which is in contrast to Syntax Tree, where both structs and unions share the same node kind, because their syntax is the same. What would be the right thing to do here? Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
1dc9adc6e2
@ -10,7 +10,7 @@
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Name, AsName, Struct, Enum, EnumVariant, Crate,
|
||||
Name, AsName, Struct, Union, Enum, EnumVariant, Crate,
|
||||
HirDatabase, HirFileId, StructField, FieldSource,
|
||||
type_ref::TypeRef, DefDatabase,
|
||||
};
|
||||
@ -18,14 +18,16 @@
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum AdtDef {
|
||||
Struct(Struct),
|
||||
Union(Union),
|
||||
Enum(Enum),
|
||||
}
|
||||
impl_froms!(AdtDef: Struct, Enum);
|
||||
impl_froms!(AdtDef: Struct, Union, Enum);
|
||||
|
||||
impl AdtDef {
|
||||
pub(crate) fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
|
||||
match self {
|
||||
AdtDef::Struct(s) => s.module(db),
|
||||
AdtDef::Union(s) => s.module(db),
|
||||
AdtDef::Enum(e) => e.module(db),
|
||||
}
|
||||
.krate(db)
|
||||
@ -38,6 +40,7 @@ pub(crate) fn variant_data(&self, db: &impl DefDatabase) -> Arc<VariantData> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Note that we use `StructData` for unions as well!
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct StructData {
|
||||
pub(crate) name: Option<Name>,
|
||||
|
@ -71,6 +71,7 @@ pub enum ModuleDef {
|
||||
Module(Module),
|
||||
Function(Function),
|
||||
Struct(Struct),
|
||||
Union(Union),
|
||||
Enum(Enum),
|
||||
// Can't be directly declared, but can be imported.
|
||||
EnumVariant(EnumVariant),
|
||||
@ -83,6 +84,7 @@ pub enum ModuleDef {
|
||||
ModuleDef: Module,
|
||||
Function,
|
||||
Struct,
|
||||
Union,
|
||||
Enum,
|
||||
EnumVariant,
|
||||
Const,
|
||||
@ -325,6 +327,42 @@ fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Union {
|
||||
pub(crate) id: StructId,
|
||||
}
|
||||
|
||||
impl Union {
|
||||
pub fn source(&self, db: &impl DefDatabase) -> (HirFileId, TreeArc<ast::StructDef>) {
|
||||
self.id.source(db)
|
||||
}
|
||||
|
||||
pub fn name(&self, db: &impl HirDatabase) -> Option<Name> {
|
||||
db.struct_data(Struct { id: self.id }).name.clone()
|
||||
}
|
||||
|
||||
pub fn module(&self, db: &impl HirDatabase) -> Module {
|
||||
self.id.module(db)
|
||||
}
|
||||
|
||||
// FIXME move to a more general type
|
||||
/// Builds a resolver for type references inside this union.
|
||||
pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver {
|
||||
// take the outer scope...
|
||||
let r = self.module(db).resolver(db);
|
||||
// ...and add generic params, if present
|
||||
let p = self.generic_params(db);
|
||||
let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r };
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
impl Docs for Union {
|
||||
fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> {
|
||||
docs_from_ast(&*self.source(db).1)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Enum {
|
||||
pub(crate) id: EnumId,
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
use crate::{
|
||||
db::{ HirDatabase, DefDatabase},
|
||||
Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock, Container, path::Path, type_ref::TypeRef, AdtDef
|
||||
Name, AsName, Function, Struct, Union, Enum, Trait, TypeAlias, ImplBlock, Container, path::Path, type_ref::TypeRef, AdtDef
|
||||
};
|
||||
|
||||
/// Data about a generic parameter (to a function, struct, impl, ...).
|
||||
@ -42,12 +42,13 @@ pub struct WherePredicate {
|
||||
pub enum GenericDef {
|
||||
Function(Function),
|
||||
Struct(Struct),
|
||||
Union(Union),
|
||||
Enum(Enum),
|
||||
Trait(Trait),
|
||||
TypeAlias(TypeAlias),
|
||||
ImplBlock(ImplBlock),
|
||||
}
|
||||
impl_froms!(GenericDef: Function, Struct, Enum, Trait, TypeAlias, ImplBlock);
|
||||
impl_froms!(GenericDef: Function, Struct, Union, Enum, Trait, TypeAlias, ImplBlock);
|
||||
|
||||
impl GenericParams {
|
||||
pub(crate) fn generic_params_query(
|
||||
@ -58,7 +59,10 @@ pub(crate) fn generic_params_query(
|
||||
let parent = match def {
|
||||
GenericDef::Function(it) => it.container(db).map(GenericDef::from),
|
||||
GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from),
|
||||
GenericDef::Struct(_) | GenericDef::Enum(_) | GenericDef::Trait(_) => None,
|
||||
GenericDef::Struct(_)
|
||||
| GenericDef::Union(_)
|
||||
| GenericDef::Enum(_)
|
||||
| GenericDef::Trait(_) => None,
|
||||
GenericDef::ImplBlock(_) => None,
|
||||
};
|
||||
generics.parent_params = parent.map(|p| db.generic_params(p));
|
||||
@ -66,6 +70,7 @@ pub(crate) fn generic_params_query(
|
||||
match def {
|
||||
GenericDef::Function(it) => generics.fill(&*it.source(db).1, start),
|
||||
GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start),
|
||||
GenericDef::Union(it) => generics.fill(&*it.source(db).1, start),
|
||||
GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start),
|
||||
GenericDef::Trait(it) => {
|
||||
// traits get the Self type as an implicit first type parameter
|
||||
@ -171,6 +176,7 @@ pub(crate) fn resolver(&self, db: &impl HirDatabase) -> crate::Resolver {
|
||||
match self {
|
||||
GenericDef::Function(inner) => inner.resolver(db),
|
||||
GenericDef::Struct(inner) => inner.resolver(db),
|
||||
GenericDef::Union(inner) => inner.resolver(db),
|
||||
GenericDef::Enum(inner) => inner.resolver(db),
|
||||
GenericDef::Trait(inner) => inner.resolver(db),
|
||||
GenericDef::TypeAlias(inner) => inner.resolver(db),
|
||||
@ -192,6 +198,7 @@ impl From<crate::adt::AdtDef> for GenericDef {
|
||||
fn from(adt: crate::adt::AdtDef) -> Self {
|
||||
match adt {
|
||||
AdtDef::Struct(s) => s.into(),
|
||||
AdtDef::Union(u) => u.into(),
|
||||
AdtDef::Enum(e) => e.into(),
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ fn from(it: $v) -> $e {
|
||||
Crate, CrateDependency,
|
||||
DefWithBody,
|
||||
Module, ModuleDef, ModuleSource,
|
||||
Struct, Enum, EnumVariant,
|
||||
Struct, Union, Enum, EnumVariant,
|
||||
Function, FnSignature,
|
||||
StructField, FieldSource,
|
||||
Static, Const, ConstSignature,
|
||||
|
@ -6,7 +6,7 @@
|
||||
use ra_syntax::ast;
|
||||
|
||||
use crate::{
|
||||
Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
|
||||
Function, Module, Struct, Union, Enum, Const, Static, Trait, TypeAlias,
|
||||
DefDatabase, HirFileId, Name, Path,
|
||||
KnownName,
|
||||
nameres::{
|
||||
@ -495,6 +495,10 @@ macro_rules! def {
|
||||
let s = def!(Struct, ast_id);
|
||||
PerNs::both(s, s)
|
||||
}
|
||||
raw::DefKind::Union(ast_id) => {
|
||||
let s = def!(Union, ast_id);
|
||||
PerNs::both(s, s)
|
||||
}
|
||||
raw::DefKind::Enum(ast_id) => PerNs::types(def!(Enum, ast_id)),
|
||||
raw::DefKind::Const(ast_id) => PerNs::values(def!(Const, ast_id)),
|
||||
raw::DefKind::Static(ast_id) => PerNs::values(def!(Static, ast_id)),
|
||||
|
@ -1,7 +1,4 @@
|
||||
use std::{
|
||||
sync::Arc,
|
||||
ops::Index,
|
||||
};
|
||||
use std::{sync::Arc, ops::Index};
|
||||
|
||||
use test_utils::tested_by;
|
||||
use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap};
|
||||
@ -10,10 +7,7 @@
|
||||
ast::{self, NameOwner, AttrsOwner},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
DefDatabase, Name, AsName, Path, HirFileId, ModuleSource,
|
||||
AstIdMap, FileAstId, Either,
|
||||
};
|
||||
use crate::{DefDatabase, Name, AsName, Path, HirFileId, ModuleSource, AstIdMap, FileAstId, Either};
|
||||
|
||||
/// `RawItems` is a set of top-level items in a file (except for impls).
|
||||
///
|
||||
@ -161,6 +155,7 @@ pub(super) struct DefData {
|
||||
pub(super) enum DefKind {
|
||||
Function(FileAstId<ast::FnDef>),
|
||||
Struct(FileAstId<ast::StructDef>),
|
||||
Union(FileAstId<ast::StructDef>),
|
||||
Enum(FileAstId<ast::EnumDef>),
|
||||
Const(FileAstId<ast::ConstDef>),
|
||||
Static(FileAstId<ast::StaticDef>),
|
||||
@ -215,7 +210,13 @@ fn add_item(&mut self, current_module: Option<Module>, item: &ast::ModuleItem) {
|
||||
return;
|
||||
}
|
||||
ast::ModuleItemKind::StructDef(it) => {
|
||||
(DefKind::Struct(self.source_ast_id_map.ast_id(it)), it.name())
|
||||
let id = self.source_ast_id_map.ast_id(it);
|
||||
let name = it.name();
|
||||
if it.is_union() {
|
||||
(DefKind::Union(id), name)
|
||||
} else {
|
||||
(DefKind::Struct(id), name)
|
||||
}
|
||||
}
|
||||
ast::ModuleItemKind::EnumDef(it) => {
|
||||
(DefKind::Enum(self.source_ast_id_map.ast_id(it)), it.name())
|
||||
|
@ -536,6 +536,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||
TypeCtor::Adt(def_id) => {
|
||||
let name = match def_id {
|
||||
AdtDef::Struct(s) => s.name(f.db),
|
||||
AdtDef::Union(u) => u.name(f.db),
|
||||
AdtDef::Enum(e) => e.name(f.db),
|
||||
}
|
||||
.unwrap_or_else(Name::missing);
|
||||
|
@ -27,13 +27,13 @@
|
||||
use test_utils::tested_by;
|
||||
|
||||
use crate::{
|
||||
Function, StructField, Path, Name,
|
||||
FnSignature, AdtDef,ConstSignature,
|
||||
HirDatabase,
|
||||
DefWithBody,
|
||||
ImplItem,
|
||||
Function, StructField, Path, Name, FnSignature, AdtDef, ConstSignature, HirDatabase,
|
||||
DefWithBody, ImplItem,
|
||||
type_ref::{TypeRef, Mutability},
|
||||
expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat,Array, self},
|
||||
expr::{
|
||||
Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement,
|
||||
FieldPat, Array, self,
|
||||
},
|
||||
generics::{GenericParams, HasGenericParams},
|
||||
path::{GenericArgs, GenericArg},
|
||||
ModuleDef,
|
||||
@ -644,7 +644,8 @@ fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) {
|
||||
let ty = self.insert_type_vars(ty.apply_substs(substs));
|
||||
(ty, Some(var.into()))
|
||||
}
|
||||
TypableDef::TypeAlias(_)
|
||||
TypableDef::Union(_)
|
||||
| TypableDef::TypeAlias(_)
|
||||
| TypableDef::Function(_)
|
||||
| TypableDef::Enum(_)
|
||||
| TypableDef::Const(_)
|
||||
@ -1407,7 +1408,11 @@ fn none() -> Self {
|
||||
}
|
||||
|
||||
mod diagnostics {
|
||||
use crate::{expr::ExprId, diagnostics::{DiagnosticSink, NoSuchField}, HirDatabase, Function};
|
||||
use crate::{
|
||||
expr::ExprId,
|
||||
diagnostics::{DiagnosticSink, NoSuchField},
|
||||
HirDatabase, Function,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub(super) enum InferenceDiagnostic {
|
||||
|
@ -9,7 +9,7 @@
|
||||
use std::iter;
|
||||
|
||||
use crate::{
|
||||
Function, Struct, StructField, Enum, EnumVariant, Path, ModuleDef, TypeAlias, Const, Static,
|
||||
Function, Struct, Union, StructField, Enum, EnumVariant, Path, ModuleDef, TypeAlias, Const, Static,
|
||||
HirDatabase,
|
||||
type_ref::TypeRef,
|
||||
name::KnownName,
|
||||
@ -124,6 +124,7 @@ pub(super) fn substs_from_path_segment(
|
||||
let def_generic: Option<GenericDef> = match resolved {
|
||||
TypableDef::Function(func) => Some(func.into()),
|
||||
TypableDef::Struct(s) => Some(s.into()),
|
||||
TypableDef::Union(u) => Some(u.into()),
|
||||
TypableDef::Enum(e) => Some(e.into()),
|
||||
TypableDef::EnumVariant(var) => Some(var.parent_enum(db).into()),
|
||||
TypableDef::TypeAlias(t) => Some(t.into()),
|
||||
@ -144,6 +145,7 @@ pub(super) fn substs_from_path(
|
||||
let segment = match resolved {
|
||||
TypableDef::Function(_)
|
||||
| TypableDef::Struct(_)
|
||||
| TypableDef::Union(_)
|
||||
| TypableDef::Enum(_)
|
||||
| TypableDef::Const(_)
|
||||
| TypableDef::Static(_)
|
||||
@ -293,12 +295,14 @@ pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace
|
||||
(TypableDef::Struct(s), Namespace::Values) => type_for_struct_constructor(db, s),
|
||||
(TypableDef::Enum(e), Namespace::Types) => type_for_adt(db, e),
|
||||
(TypableDef::EnumVariant(v), Namespace::Values) => type_for_enum_variant_constructor(db, v),
|
||||
(TypableDef::Union(u), Namespace::Types) => type_for_adt(db, u),
|
||||
(TypableDef::TypeAlias(t), Namespace::Types) => type_for_type_alias(db, t),
|
||||
(TypableDef::Const(c), Namespace::Values) => type_for_const(db, c),
|
||||
(TypableDef::Static(c), Namespace::Values) => type_for_static(db, c),
|
||||
|
||||
// 'error' cases:
|
||||
(TypableDef::Function(_), Namespace::Types) => Ty::Unknown,
|
||||
(TypableDef::Union(_), Namespace::Values) => Ty::Unknown,
|
||||
(TypableDef::Enum(_), Namespace::Values) => Ty::Unknown,
|
||||
(TypableDef::EnumVariant(_), Namespace::Types) => Ty::Unknown,
|
||||
(TypableDef::TypeAlias(_), Namespace::Values) => Ty::Unknown,
|
||||
@ -467,19 +471,21 @@ fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty {
|
||||
pub enum TypableDef {
|
||||
Function(Function),
|
||||
Struct(Struct),
|
||||
Union(Union),
|
||||
Enum(Enum),
|
||||
EnumVariant(EnumVariant),
|
||||
TypeAlias(TypeAlias),
|
||||
Const(Const),
|
||||
Static(Static),
|
||||
}
|
||||
impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant, TypeAlias, Const, Static);
|
||||
impl_froms!(TypableDef: Function, Struct, Union, Enum, EnumVariant, TypeAlias, Const, Static);
|
||||
|
||||
impl From<ModuleDef> for Option<TypableDef> {
|
||||
fn from(def: ModuleDef) -> Option<TypableDef> {
|
||||
let res = match def {
|
||||
ModuleDef::Function(f) => f.into(),
|
||||
ModuleDef::Struct(s) => s.into(),
|
||||
ModuleDef::Union(u) => u.into(),
|
||||
ModuleDef::Enum(e) => e.into(),
|
||||
ModuleDef::EnumVariant(v) => v.into(),
|
||||
ModuleDef::TypeAlias(t) => t.into(),
|
||||
|
@ -20,6 +20,7 @@ pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionCon
|
||||
}
|
||||
|
||||
// FIXME unions
|
||||
AdtDef::Union(_) => (),
|
||||
AdtDef::Enum(_) => (),
|
||||
};
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ pub(crate) fn add_resolution(
|
||||
return self.add_function_with_name(ctx, Some(local_name), *func);
|
||||
}
|
||||
Resolution::Def(Struct(it)) => (CompletionItemKind::Struct, it.docs(ctx.db)),
|
||||
Resolution::Def(Union(it)) => (CompletionItemKind::Struct, it.docs(ctx.db)),
|
||||
Resolution::Def(Enum(it)) => (CompletionItemKind::Enum, it.docs(ctx.db)),
|
||||
Resolution::Def(EnumVariant(it)) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)),
|
||||
Resolution::Def(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)),
|
||||
|
@ -154,6 +154,10 @@ pub(crate) fn from_adt_def(db: &RootDatabase, adt_def: hir::AdtDef) -> Navigatio
|
||||
let (file_id, node) = s.source(db);
|
||||
NavigationTarget::from_named(file_id.original_file(db), &*node)
|
||||
}
|
||||
hir::AdtDef::Union(s) => {
|
||||
let (file_id, node) = s.source(db);
|
||||
NavigationTarget::from_named(file_id.original_file(db), &*node)
|
||||
}
|
||||
hir::AdtDef::Enum(s) => {
|
||||
let (file_id, node) = s.source(db);
|
||||
NavigationTarget::from_named(file_id.original_file(db), &*node)
|
||||
@ -169,6 +173,10 @@ pub(crate) fn from_def(db: &RootDatabase, module_def: hir::ModuleDef) -> Navigat
|
||||
let (file_id, node) = s.source(db);
|
||||
NavigationTarget::from_named(file_id.original_file(db), &*node)
|
||||
}
|
||||
hir::ModuleDef::Union(s) => {
|
||||
let (file_id, node) = s.source(db);
|
||||
NavigationTarget::from_named(file_id.original_file(db), &*node)
|
||||
}
|
||||
hir::ModuleDef::Const(s) => {
|
||||
let (file_id, node) = s.source(db);
|
||||
NavigationTarget::from_named(file_id.original_file(db), &*node)
|
||||
|
@ -57,6 +57,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
|
||||
Some(Def(ModuleDef::Module(_))) => "module",
|
||||
Some(Def(ModuleDef::Function(_))) => "function",
|
||||
Some(Def(ModuleDef::Struct(_))) => "type",
|
||||
Some(Def(ModuleDef::Union(_))) => "type",
|
||||
Some(Def(ModuleDef::Enum(_))) => "type",
|
||||
Some(Def(ModuleDef::EnumVariant(_))) => "constant",
|
||||
Some(Def(ModuleDef::Const(_))) => "constant",
|
||||
|
Loading…
Reference in New Issue
Block a user