Skip to content

Commit

Permalink
Support recursive types (#2178)
Browse files Browse the repository at this point in the history
  • Loading branch information
spapinistarkware committed Feb 18, 2023
1 parent 76bb712 commit 3ef87ab
Show file tree
Hide file tree
Showing 7 changed files with 289 additions and 122 deletions.
96 changes: 70 additions & 26 deletions crates/cairo-lang-semantic/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,49 +146,85 @@ pub trait SemanticGroup:

// Struct.
// =======
/// Private query to compute data about a struct.
#[salsa::invoke(items::structure::priv_struct_semantic_data)]
fn priv_struct_semantic_data(&self, struct_id: StructId)
-> Maybe<items::structure::StructData>;
/// Returns the semantic diagnostics of a struct.
#[salsa::invoke(items::structure::struct_semantic_diagnostics)]
fn struct_semantic_diagnostics(&self, struct_id: StructId) -> Diagnostics<SemanticDiagnostic>;
/// Private query to compute data about a struct declaration.
#[salsa::invoke(items::structure::priv_struct_declaration_data)]
fn priv_struct_declaration_data(
&self,
struct_id: StructId,
) -> Maybe<items::structure::StructDeclarationData>;
/// Returns the declaration diagnostics of a struct.
#[salsa::invoke(items::structure::struct_declaration_diagnostics)]
fn struct_declaration_diagnostics(
&self,
struct_id: StructId,
) -> Diagnostics<SemanticDiagnostic>;
/// Returns the attributes of a struct.
#[salsa::invoke(items::structure::struct_attributes)]
fn struct_attributes(&self, struct_id: StructId) -> Maybe<Vec<Attribute>>;
/// Returns the generic parameters of an enum.
#[salsa::invoke(items::structure::struct_generic_params)]
fn struct_generic_params(&self, struct_id: StructId) -> Maybe<Vec<GenericParam>>;
/// Returns the resolution lookback of a struct declaration.
#[salsa::invoke(items::structure::struct_declaration_resolved_lookback)]
fn struct_declaration_resolved_lookback(
&self,
structure_id: StructId,
) -> Maybe<Arc<ResolvedLookback>>;

/// Private query to compute data about a struct definition.
#[salsa::invoke(items::structure::priv_struct_definition_data)]
fn priv_struct_definition_data(
&self,
struct_id: StructId,
) -> Maybe<items::structure::StructDefinitionData>;
/// Returns the semantic diagnostics of a struct definition.
#[salsa::invoke(items::structure::struct_definition_diagnostics)]
fn struct_definition_diagnostics(&self, struct_id: StructId)
-> Diagnostics<SemanticDiagnostic>;
/// Returns the members of a struct.
#[salsa::invoke(items::structure::struct_members)]
fn struct_members(
&self,
struct_id: StructId,
) -> Maybe<OrderedHashMap<SmolStr, semantic::Member>>;
/// Returns the attributes of a struct.
#[salsa::invoke(items::structure::struct_attributes)]
fn struct_attributes(&self, struct_id: StructId) -> Maybe<Vec<Attribute>>;
/// Returns the resolution lookback of a struct.
#[salsa::invoke(items::structure::struct_resolved_lookback)]
fn struct_resolved_lookback(&self, structure_id: StructId) -> Maybe<Arc<ResolvedLookback>>;
/// Returns the resolution lookback of a struct definition.
#[salsa::invoke(items::structure::struct_definition_resolved_lookback)]
fn struct_definition_resolved_lookback(
&self,
structure_id: StructId,
) -> Maybe<Arc<ResolvedLookback>>;

// Enum.
// =======
/// Private query to compute data about an enum.
#[salsa::invoke(items::enm::priv_enum_semantic_data)]
fn priv_enum_semantic_data(&self, enum_id: EnumId) -> Maybe<items::enm::EnumData>;
/// Returns the semantic diagnostics of an enum.
#[salsa::invoke(items::enm::enum_semantic_diagnostics)]
fn enum_semantic_diagnostics(&self, enum_id: EnumId) -> Diagnostics<SemanticDiagnostic>;
/// Private query to compute data about an enum declaration.
#[salsa::invoke(items::enm::priv_enum_declaration_data)]
fn priv_enum_declaration_data(&self, enum_id: EnumId)
-> Maybe<items::enm::EnumDeclarationData>;
/// Returns the diagnostics of an enum declaration.
#[salsa::invoke(items::enm::enum_declaration_diagnostics)]
fn enum_declaration_diagnostics(&self, enum_id: EnumId) -> Diagnostics<SemanticDiagnostic>;
/// Returns the generic parameters of an enum.
#[salsa::invoke(items::enm::enum_generic_params)]
fn enum_generic_params(&self, enum_id: EnumId) -> Maybe<Vec<GenericParam>>;
/// Returns the resolution lookback of an enum declaration.
#[salsa::invoke(items::enm::enum_declaration_resolved_lookback)]
fn enum_declaration_resolved_lookback(&self, enum_id: EnumId) -> Maybe<Arc<ResolvedLookback>>;

/// Private query to compute data about an enum definition.
#[salsa::invoke(items::enm::priv_enum_definition_data)]
fn priv_enum_definition_data(&self, enum_id: EnumId) -> Maybe<items::enm::EnumDefinitionData>;
/// Returns the definition diagnostics of an enum definition.
#[salsa::invoke(items::enm::enum_definition_diagnostics)]
fn enum_definition_diagnostics(&self, enum_id: EnumId) -> Diagnostics<SemanticDiagnostic>;
/// Returns the members of an enum.
#[salsa::invoke(items::enm::enum_variants)]
fn enum_variants(&self, enum_id: EnumId) -> Maybe<OrderedHashMap<SmolStr, VariantId>>;
/// Returns the semantic model of a variant.
#[salsa::invoke(items::enm::variant_semantic)]
fn variant_semantic(&self, enum_id: EnumId, variant_id: VariantId) -> Maybe<semantic::Variant>;
/// Returns the resolution lookback of an enum.
#[salsa::invoke(items::enm::enum_resolved_lookback)]
fn enum_resolved_lookback(&self, enum_id: EnumId) -> Maybe<Arc<ResolvedLookback>>;
/// Returns the resolution lookback of an enum definition.
#[salsa::invoke(items::enm::enum_definition_resolved_lookback)]
fn enum_definition_resolved_lookback(&self, enum_id: EnumId) -> Maybe<Arc<ResolvedLookback>>;

// Type Alias.
// ====
Expand Down Expand Up @@ -742,10 +778,12 @@ fn module_semantic_diagnostics(
diagnostics.extend(db.free_function_body_diagnostics(*free_function));
}
ModuleItemId::Struct(struct_id) => {
diagnostics.extend(db.struct_semantic_diagnostics(*struct_id));
diagnostics.extend(db.struct_declaration_diagnostics(*struct_id));
diagnostics.extend(db.struct_definition_diagnostics(*struct_id));
}
ModuleItemId::Enum(enum_id) => {
diagnostics.extend(db.enum_semantic_diagnostics(*enum_id));
diagnostics.extend(db.enum_definition_diagnostics(*enum_id));
diagnostics.extend(db.enum_declaration_diagnostics(*enum_id));
}
ModuleItemId::Trait(trait_id) => {
diagnostics.extend(db.trait_semantic_diagnostics(*trait_id));
Expand Down Expand Up @@ -896,8 +934,14 @@ fn get_resolver_lookbacks(id: LookupItemId, db: &dyn SemanticGroup) -> Vec<Arc<R
db.free_function_declaration_resolved_lookback(id),
db.free_function_body_resolved_lookback(id),
],
ModuleItemId::Struct(id) => vec![db.struct_resolved_lookback(id)],
ModuleItemId::Enum(id) => vec![db.enum_resolved_lookback(id)],
ModuleItemId::Struct(id) => vec![
db.struct_declaration_resolved_lookback(id),
db.struct_definition_resolved_lookback(id),
],
ModuleItemId::Enum(id) => vec![
db.enum_definition_resolved_lookback(id),
db.enum_declaration_resolved_lookback(id),
],
ModuleItemId::TypeAlias(id) => vec![db.type_alias_resolved_lookback(id)],
ModuleItemId::Trait(_) => vec![],
ModuleItemId::Impl(id) => vec![db.impl_def_resolved_lookback(id)],
Expand Down
165 changes: 113 additions & 52 deletions crates/cairo-lang-semantic/src/items/enm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use cairo_lang_utils::Upcast;
use itertools::enumerate;
use smol_str::SmolStr;

use super::attribute::{ast_attributes_to_semantic, Attribute};
use super::generics::semantic_generic_params;
use crate::db::SemanticGroup;
use crate::diagnostic::SemanticDiagnosticKind::*;
Expand All @@ -21,11 +22,80 @@ use crate::{semantic, ConcreteEnumId, SemanticDiagnostic};
#[path = "enm_test.rs"]
mod test;

// Declaration
#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
#[debug_db(dyn SemanticGroup + 'static)]
pub struct EnumData {
pub struct EnumDeclarationData {
diagnostics: Diagnostics<SemanticDiagnostic>,
generic_params: Vec<semantic::GenericParam>,
attributes: Vec<Attribute>,
resolved_lookback: Arc<ResolvedLookback>,
}

/// Query implementation of [crate::db::SemanticGroup::priv_enum_declaration_data].
pub fn priv_enum_declaration_data(
db: &dyn SemanticGroup,
enum_id: EnumId,
) -> Maybe<EnumDeclarationData> {
let module_file_id = enum_id.module_file_id(db.upcast());
let mut diagnostics = SemanticDiagnostics::new(module_file_id);
// TODO(spapini): when code changes in a file, all the AST items change (as they contain a path
// to the green root that changes. Once ASTs are rooted on items, use a selector that picks only
// the item instead of all the module data.
let module_enums = db.module_enums(module_file_id.0)?;
let enum_ast = module_enums.get(&enum_id).to_maybe()?;
let syntax_db = db.upcast();

// Generic params.
let mut resolver = Resolver::new_with_inference(db, module_file_id);
let generic_params = semantic_generic_params(
db,
&mut diagnostics,
&mut resolver,
module_file_id,
&enum_ast.generic_params(db.upcast()),
);

let attributes = ast_attributes_to_semantic(syntax_db, enum_ast.attributes(syntax_db));
let resolved_lookback = Arc::new(resolver.lookback);

Ok(EnumDeclarationData {
diagnostics: diagnostics.build(),
generic_params,
attributes,
resolved_lookback,
})
}

/// Query implementation of [crate::db::SemanticGroup::enum_declaration_diagnostics].
pub fn enum_declaration_diagnostics(
db: &dyn SemanticGroup,
enum_id: EnumId,
) -> Diagnostics<SemanticDiagnostic> {
db.priv_enum_declaration_data(enum_id).map(|data| data.diagnostics).unwrap_or_default()
}

/// Query implementation of [crate::db::SemanticGroup::enum_generic_params].
pub fn enum_generic_params(
db: &dyn SemanticGroup,
enum_id: EnumId,
) -> Maybe<Vec<semantic::GenericParam>> {
Ok(db.priv_enum_declaration_data(enum_id)?.generic_params)
}

/// Query implementation of [crate::db::SemanticGroup::enum_declaration_resolved_lookback].
pub fn enum_declaration_resolved_lookback(
db: &dyn SemanticGroup,
enum_id: EnumId,
) -> Maybe<Arc<ResolvedLookback>> {
Ok(db.priv_enum_declaration_data(enum_id)?.resolved_lookback)
}

// Definition
#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
#[debug_db(dyn SemanticGroup + 'static)]
pub struct EnumDefinitionData {
diagnostics: Diagnostics<SemanticDiagnostic>,
variants: OrderedHashMap<SmolStr, VariantId>,
variant_semantic: OrderedHashMap<VariantId, Variant>,
resolved_lookback: Arc<ResolvedLookback>,
Expand All @@ -51,50 +121,11 @@ pub struct ConcreteVariant {
pub idx: usize,
}

/// Query implementation of [crate::db::SemanticGroup::enum_semantic_diagnostics].
pub fn enum_semantic_diagnostics(
db: &dyn SemanticGroup,
enum_id: EnumId,
) -> Diagnostics<SemanticDiagnostic> {
db.priv_enum_semantic_data(enum_id).map(|data| data.diagnostics).unwrap_or_default()
}

/// Query implementation of [crate::db::SemanticGroup::enum_generic_params].
pub fn enum_generic_params(
db: &dyn SemanticGroup,
enum_id: EnumId,
) -> Maybe<Vec<semantic::GenericParam>> {
Ok(db.priv_enum_semantic_data(enum_id)?.generic_params)
}

/// Query implementation of [crate::db::SemanticGroup::enum_variants].
pub fn enum_variants(
db: &dyn SemanticGroup,
enum_id: EnumId,
) -> Maybe<OrderedHashMap<SmolStr, VariantId>> {
Ok(db.priv_enum_semantic_data(enum_id)?.variants)
}

/// Query implementation of [crate::db::SemanticGroup::variant_semantic].
pub fn variant_semantic(
db: &dyn SemanticGroup,
enum_id: EnumId,
variant_id: VariantId,
) -> Maybe<Variant> {
let data = db.priv_enum_semantic_data(enum_id)?;
data.variant_semantic.get(&variant_id).cloned().to_maybe()
}

/// Query implementation of [crate::db::SemanticGroup::enum_resolved_lookback].
pub fn enum_resolved_lookback(
/// Query implementation of [crate::db::SemanticGroup::priv_enum_definition_data].
pub fn priv_enum_definition_data(
db: &dyn SemanticGroup,
enum_id: EnumId,
) -> Maybe<Arc<ResolvedLookback>> {
Ok(db.priv_enum_semantic_data(enum_id)?.resolved_lookback)
}

/// Query implementation of [crate::db::SemanticGroup::priv_enum_semantic_data].
pub fn priv_enum_semantic_data(db: &dyn SemanticGroup, enum_id: EnumId) -> Maybe<EnumData> {
) -> Maybe<EnumDefinitionData> {
let module_file_id = enum_id.module_file_id(db.upcast());
let mut diagnostics = SemanticDiagnostics::new(module_file_id);
// TODO(spapini): when code changes in a file, all the AST items change (as they contain a path
Expand All @@ -106,13 +137,10 @@ pub fn priv_enum_semantic_data(db: &dyn SemanticGroup, enum_id: EnumId) -> Maybe

// Generic params.
let mut resolver = Resolver::new_with_inference(db, module_file_id);
let generic_params = semantic_generic_params(
db,
&mut diagnostics,
&mut resolver,
module_file_id,
&enum_ast.generic_params(db.upcast()),
);
let generic_params = db.enum_generic_params(enum_id)?;
for generic_param in generic_params {
resolver.add_generic_param(generic_param);
}

// Variants.
let mut variants = OrderedHashMap::default();
Expand All @@ -134,15 +162,48 @@ pub fn priv_enum_semantic_data(db: &dyn SemanticGroup, enum_id: EnumId) -> Maybe

let resolved_lookback = Arc::new(resolver.lookback);

Ok(EnumData {
Ok(EnumDefinitionData {
diagnostics: diagnostics.build(),
generic_params,
variants,
variant_semantic,
resolved_lookback,
})
}

/// Query implementation of [crate::db::SemanticGroup::enum_definition_diagnostics].
pub fn enum_definition_diagnostics(
db: &dyn SemanticGroup,
enum_id: EnumId,
) -> Diagnostics<SemanticDiagnostic> {
db.priv_enum_definition_data(enum_id).map(|data| data.diagnostics).unwrap_or_default()
}

/// Query implementation of [crate::db::SemanticGroup::enum_definition_resolved_lookback].
pub fn enum_definition_resolved_lookback(
db: &dyn SemanticGroup,
enum_id: EnumId,
) -> Maybe<Arc<ResolvedLookback>> {
Ok(db.priv_enum_definition_data(enum_id)?.resolved_lookback)
}

/// Query implementation of [crate::db::SemanticGroup::enum_variants].
pub fn enum_variants(
db: &dyn SemanticGroup,
enum_id: EnumId,
) -> Maybe<OrderedHashMap<SmolStr, VariantId>> {
Ok(db.priv_enum_definition_data(enum_id)?.variants)
}

/// Query implementation of [crate::db::SemanticGroup::variant_semantic].
pub fn variant_semantic(
db: &dyn SemanticGroup,
enum_id: EnumId,
variant_id: VariantId,
) -> Maybe<Variant> {
let data = db.priv_enum_definition_data(enum_id)?;
data.variant_semantic.get(&variant_id).cloned().to_maybe()
}

// TODO(spapini): Consider making these queries.
pub trait SemanticEnumEx<'a>: Upcast<dyn SemanticGroup + 'a> {
/// Retrieves the [ConcreteVariant] for a [ConcreteEnumId] and a [Variant].
Expand Down
Loading

0 comments on commit 3ef87ab

Please sign in to comment.