From 2ca039d884a4d2bf354230c52b3e533b7ca7e998 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Fri, 9 Sep 2022 14:00:58 +0100 Subject: [PATCH] Add structs declarations to the declaration engine. --- .../dead_code_analysis.rs | 15 +++--- .../declaration_engine/declaration_engine.rs | 2 +- .../semantic_analysis/ast_node/declaration.rs | 53 +++++++++++++++---- .../match_expression/typed/typed_scrutinee.rs | 2 +- .../src/semantic_analysis/ast_node/mod.rs | 4 +- .../src/semantic_analysis/namespace/items.rs | 2 +- .../src/semantic_analysis/namespace/root.rs | 32 ++++++++--- .../semantic_analysis/storage_only_types.rs | 8 ++- sway-core/src/type_system/type_binding.rs | 24 +++++++-- sway-lsp/src/capabilities/hover.rs | 5 +- sway-lsp/src/core/traverse_typed_tree.rs | 13 +++-- sway-lsp/src/utils/token.rs | 4 +- 12 files changed, 125 insertions(+), 39 deletions(-) diff --git a/sway-core/src/control_flow_analysis/dead_code_analysis.rs b/sway-core/src/control_flow_analysis/dead_code_analysis.rs index 1648df7608a..cba934297db 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -170,13 +170,13 @@ impl ControlFlowGraph { ControlFlowGraphNode::ProgramNode(TypedAstNode { content: TypedAstNodeContent::Declaration(TypedDeclaration::StructDeclaration( - TypedStructDeclaration { - visibility: Visibility::Public, - .. - }, + decl_id, )), .. - }) => true, + }) => { + let struct_decl = de_get_struct(decl_id.clone(), &decl_id.span())?; + struct_decl.visibility == Visibility::Public + } ControlFlowGraphNode::ProgramNode(TypedAstNode { content: TypedAstNodeContent::Declaration(TypedDeclaration::ImplTrait { .. }), @@ -368,8 +368,9 @@ fn connect_declaration( connect_abi_declaration(&abi_decl, graph, entry_node); Ok(leaves.to_vec()) } - StructDeclaration(struct_decl) => { - connect_struct_declaration(struct_decl, graph, entry_node, tree_type); + StructDeclaration(decl_id) => { + let struct_decl = de_get_struct(decl_id.clone(), &span)?; + connect_struct_declaration(&struct_decl, graph, entry_node, tree_type); Ok(leaves.to_vec()) } EnumDeclaration(enum_decl) => { diff --git a/sway-core/src/declaration_engine/declaration_engine.rs b/sway-core/src/declaration_engine/declaration_engine.rs index debf88c7d45..29b809e4876 100644 --- a/sway-core/src/declaration_engine/declaration_engine.rs +++ b/sway-core/src/declaration_engine/declaration_engine.rs @@ -294,7 +294,7 @@ pub(crate) fn de_insert_struct(r#struct: TypedStructDeclaration) -> DeclarationI DECLARATION_ENGINE.insert_struct(r#struct) } -pub(crate) fn de_get_struct( +pub fn de_get_struct( index: DeclarationId, span: &Span, ) -> Result { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration.rs index ba197f4fe52..3d30441fbcf 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration.rs @@ -33,7 +33,7 @@ pub enum TypedDeclaration { ConstantDeclaration(DeclarationId), FunctionDeclaration(TypedFunctionDeclaration), TraitDeclaration(DeclarationId), - StructDeclaration(TypedStructDeclaration), + StructDeclaration(DeclarationId), EnumDeclaration(TypedEnumDeclaration), ImplTrait(DeclarationId), AbiDeclaration(DeclarationId), @@ -53,7 +53,7 @@ impl CopyTypes for TypedDeclaration { VariableDeclaration(ref mut var_decl) => var_decl.copy_types(type_mapping), FunctionDeclaration(ref mut fn_decl) => fn_decl.copy_types(type_mapping), TraitDeclaration(ref mut trait_decl) => trait_decl.copy_types(type_mapping), - StructDeclaration(ref mut struct_decl) => struct_decl.copy_types(type_mapping), + StructDeclaration(ref mut decl_id) => decl_id.copy_types(type_mapping), EnumDeclaration(ref mut enum_decl) => enum_decl.copy_types(type_mapping), ImplTrait(impl_trait) => impl_trait.copy_types(type_mapping), // generics in an ABI is unsupported by design @@ -74,7 +74,7 @@ impl Spanned for TypedDeclaration { ConstantDeclaration(decl_id) => decl_id.span(), FunctionDeclaration(TypedFunctionDeclaration { span, .. }) => span.clone(), TraitDeclaration(decl_id) => decl_id.span(), - StructDeclaration(TypedStructDeclaration { name, .. }) => name.span(), + StructDeclaration(decl_id) => decl_id.span(), EnumDeclaration(TypedEnumDeclaration { span, .. }) => span.clone(), AbiDeclaration(decl_id) => decl_id.span(), ImplTrait(decl_id) => decl_id.span(), @@ -128,8 +128,12 @@ impl fmt::Display for TypedDeclaration { Err(_) => "unknown trait".into(), } } - TypedDeclaration::StructDeclaration(TypedStructDeclaration { name, .. }) => - name.as_str().into(), + TypedDeclaration::StructDeclaration(decl_id) => { + match de_get_struct(decl_id.clone(), &decl_id.span()) { + Ok(TypedStructDeclaration { name, .. }) => name.as_str().into(), + Err(_) => "unknown struct".into(), + } + } TypedDeclaration::EnumDeclaration(TypedEnumDeclaration { name, .. }) => name.as_str().into(), _ => String::new(), @@ -249,11 +253,22 @@ impl TypedDeclaration { /// Retrieves the declaration as a struct declaration. /// /// Returns an error if `self` is not a `TypedStructDeclaration`. - pub(crate) fn expect_struct(&self) -> CompileResult<&TypedStructDeclaration> { - let warnings = vec![]; + pub(crate) fn expect_struct( + &self, + access_span: &Span, + ) -> CompileResult { + let mut warnings = vec![]; let mut errors = vec![]; match self { - TypedDeclaration::StructDeclaration(decl) => ok(decl, warnings, errors), + TypedDeclaration::StructDeclaration(decl_id) => { + let decl = check!( + CompileResult::from(de_get_struct(decl_id.clone(), access_span)), + return err(warnings, errors), + warnings, + errors + ); + ok(decl, warnings, errors) + } decl => { errors.push(CompileError::DeclIsNotAStruct { actually: decl.friendly_name().to_string(), @@ -348,7 +363,15 @@ impl TypedDeclaration { )); return err(warnings, errors); } - TypedDeclaration::StructDeclaration(decl) => decl.create_type_id(), + TypedDeclaration::StructDeclaration(decl_id) => { + let decl = check!( + CompileResult::from(de_get_struct(decl_id.clone(), &self.span())), + return err(warnings, errors), + warnings, + errors + ); + decl.create_type_id() + } TypedDeclaration::EnumDeclaration(decl) => decl.create_type_id(), TypedDeclaration::StorageDeclaration(decl_id) => { let storage_decl = check!( @@ -399,6 +422,15 @@ impl TypedDeclaration { ); visibility } + StructDeclaration(decl_id) => { + let TypedStructDeclaration { visibility, .. } = check!( + CompileResult::from(de_get_struct(decl_id.clone(), &decl_id.span())), + return err(warnings, errors), + warnings, + errors + ); + visibility + } GenericTypeForFunctionScope { .. } | ImplTrait { .. } | StorageDeclaration { .. } @@ -406,8 +438,7 @@ impl TypedDeclaration { | ErrorRecovery => Visibility::Public, VariableDeclaration(decl) => decl.mutability.visibility(), EnumDeclaration(TypedEnumDeclaration { visibility, .. }) - | FunctionDeclaration(TypedFunctionDeclaration { visibility, .. }) - | StructDeclaration(TypedStructDeclaration { visibility, .. }) => *visibility, + | FunctionDeclaration(TypedFunctionDeclaration { visibility, .. }) => *visibility, }; ok(visibility, warnings, errors) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs index 6534515af8c..d7dde2c93b6 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs @@ -71,7 +71,7 @@ impl TypedScrutinee { errors ); let mut struct_decl = check!( - unknown_decl.expect_struct().cloned(), + unknown_decl.expect_struct(&span), return err(warnings, errors), warnings, errors diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 34620569234..27893aeb364 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -312,6 +312,7 @@ impl TypedAstNode { warnings, errors ); + let name = fn_decl.name.clone(); let decl = TypedDeclaration::FunctionDeclaration(fn_decl); ctx.namespace.insert_symbol(name, decl.clone()); @@ -366,7 +367,8 @@ impl TypedAstNode { errors ); let name = decl.name.clone(); - let decl = TypedDeclaration::StructDeclaration(decl); + let decl_id = de_insert_struct(decl); + let decl = TypedDeclaration::StructDeclaration(decl_id); // insert the struct decl into namespace check!( ctx.namespace.insert_symbol(name, decl.clone()), diff --git a/sway-core/src/semantic_analysis/namespace/items.rs b/sway-core/src/semantic_analysis/namespace/items.rs index e08a2956676..e739933629c 100644 --- a/sway-core/src/semantic_analysis/namespace/items.rs +++ b/sway-core/src/semantic_analysis/namespace/items.rs @@ -95,7 +95,7 @@ impl Items { let mut warnings = vec![]; let mut errors = vec![]; // purposefully do not preemptively return errors so that the - // new definiton allows later usages to compile + // new definition allows later usages to compile if self.symbols.get(&name).is_some() { match item { TypedDeclaration::EnumDeclaration { .. } diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 7f581c21ee7..cec7abe1f9a 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -1,6 +1,9 @@ use crate::{ - error::*, semantic_analysis::*, type_system::*, CallPath, CompileResult, Ident, TypeInfo, - TypedDeclaration, TypedFunctionDeclaration, + declaration_engine::declaration_engine::{de_add_monomorphized_struct_copy, de_get_struct}, + error::*, + semantic_analysis::*, + type_system::*, + CallPath, CompileResult, Ident, TypeInfo, TypedDeclaration, TypedFunctionDeclaration, }; use super::{module::Module, namespace::Namespace, Path}; @@ -107,10 +110,19 @@ impl Root { .ok(&mut warnings, &mut errors) .cloned() { - Some(TypedDeclaration::StructDeclaration(mut decl)) => { + Some(TypedDeclaration::StructDeclaration(original_id)) => { + // get the copy from the declaration engine + let mut new_copy = check!( + CompileResult::from(de_get_struct(original_id.clone(), &name.span())), + return err(warnings, errors), + warnings, + errors + ); + + // monomorphize the copy, in place check!( monomorphize( - &mut decl, + &mut new_copy, &mut type_arguments.unwrap_or_default(), enforce_type_arguments, span, @@ -119,9 +131,17 @@ impl Root { ), return err(warnings, errors), warnings, - errors + errors, ); - decl.create_type_id() + + // create the type id from the copy + let type_id = new_copy.create_type_id(); + + // add the new copy as a monomorphized copy of the original id + de_add_monomorphized_struct_copy(original_id, new_copy); + + // return the id + type_id } Some(TypedDeclaration::EnumDeclaration(mut decl)) => { check!( diff --git a/sway-core/src/semantic_analysis/storage_only_types.rs b/sway-core/src/semantic_analysis/storage_only_types.rs index 4363f346be9..92a4b11f354 100644 --- a/sway-core/src/semantic_analysis/storage_only_types.rs +++ b/sway-core/src/semantic_analysis/storage_only_types.rs @@ -232,7 +232,13 @@ fn decl_validate(decl: &TypedDeclaration) -> CompileResult<()> { ) } } - TypedDeclaration::StructDeclaration(TypedStructDeclaration { fields, .. }) => { + TypedDeclaration::StructDeclaration(decl_id) => { + let TypedStructDeclaration { fields, .. } = check!( + CompileResult::from(de_get_struct(decl_id.clone(), &decl_id.span())), + return err(warnings, errors), + warnings, + errors, + ); for field in fields { check!( check_type(field.type_id, field.span.clone(), false), diff --git a/sway-core/src/type_system/type_binding.rs b/sway-core/src/type_system/type_binding.rs index 252d3e40ca0..da847e3d151 100644 --- a/sway-core/src/type_system/type_binding.rs +++ b/sway-core/src/type_system/type_binding.rs @@ -1,6 +1,7 @@ use sway_types::{Span, Spanned}; use crate::{ + declaration_engine::{de_insert_struct, declaration_engine::de_get_struct}, error::{err, ok}, semantic_analysis::TypeCheckContext, type_system::{insert_type, EnforceTypeArguments}, @@ -174,10 +175,19 @@ impl TypeBinding { errors ) } - TypedDeclaration::StructDeclaration(ref mut decl) => { + TypedDeclaration::StructDeclaration(ref original_id) => { + // get the copy from the declaration engine + let mut new_copy = check!( + CompileResult::from(de_get_struct(original_id.clone(), &self.span())), + return err(warnings, errors), + warnings, + errors + ); + + // monomorphize the copy, in place check!( ctx.monomorphize( - decl, + &mut new_copy, &mut self.type_arguments, EnforceTypeArguments::No, &self.span @@ -185,7 +195,15 @@ impl TypeBinding { return err(warnings, errors), warnings, errors - ) + ); + + // insert the new copy into the declaration engine + let new_id = de_insert_struct(new_copy); + + // add the new copy as a monomorphized copy of the original id + de_add_monomorphized_copy(original_id, new_id.clone()); + + TypedDeclaration::StructDeclaration(new_id) } _ => {} } diff --git a/sway-lsp/src/capabilities/hover.rs b/sway-lsp/src/capabilities/hover.rs index a5fa1a370ff..8236c63b503 100644 --- a/sway-lsp/src/capabilities/hover.rs +++ b/sway-lsp/src/capabilities/hover.rs @@ -62,7 +62,10 @@ fn hover_format(token: &Token, ident: &Ident) -> Hover { format_variable_hover(var_decl.mutability.is_mutable(), type_name) } TypedDeclaration::FunctionDeclaration(func) => extract_fn_signature(&func.span()), - TypedDeclaration::StructDeclaration(ref struct_decl) => { + TypedDeclaration::StructDeclaration(decl_id) => { + // TODO: do not use unwrap + let struct_decl = + declaration_engine::de_get_struct(decl_id.clone(), &decl.span()).unwrap(); format_visibility_hover(struct_decl.visibility, decl.friendly_name()) } TypedDeclaration::TraitDeclaration(ref decl_id) => { diff --git a/sway-lsp/src/core/traverse_typed_tree.rs b/sway-lsp/src/core/traverse_typed_tree.rs index bb9de6a770e..690ad1669ff 100644 --- a/sway-lsp/src/core/traverse_typed_tree.rs +++ b/sway-lsp/src/core/traverse_typed_tree.rs @@ -5,7 +5,7 @@ use crate::{ utils::token::{struct_declaration_of_type_id, to_ident_key}, }; use sway_core::{ - declaration_engine::{self, de_get_impl_trait}, + declaration_engine, semantic_analysis::ast_node::{ code_block::TypedCodeBlock, expression::{ @@ -72,12 +72,15 @@ fn handle_declaration(declaration: &TypedDeclaration, tokens: &TokenMap) { collect_typed_trait_fn_token(trait_fn, tokens); } } - TypedDeclaration::StructDeclaration(struct_dec) => { - if let Some(mut token) = tokens.get_mut(&to_ident_key(&struct_dec.name)) { + TypedDeclaration::StructDeclaration(decl_id) => { + // TODO: do not use unwrap + let struct_decl = + declaration_engine::de_get_struct(decl_id.clone(), &declaration.span()).unwrap(); + if let Some(mut token) = tokens.get_mut(&to_ident_key(&struct_decl.name)) { token.typed = Some(TypedAstToken::TypedDeclaration(declaration.clone())); } - for field in &struct_dec.fields { + for field in &struct_decl.fields { if let Some(mut token) = tokens.get_mut(&to_ident_key(&field.name)) { token.typed = Some(TypedAstToken::TypedStructField(field.clone())); token.type_def = Some(TypeDefinition::TypeId(field.type_id)); @@ -91,7 +94,7 @@ fn handle_declaration(declaration: &TypedDeclaration, tokens: &TokenMap) { } } - for type_param in &struct_dec.type_parameters { + for type_param in &struct_decl.type_parameters { if let Some(mut token) = tokens.get_mut(&to_ident_key(&type_param.name_ident)) { token.typed = Some(TypedAstToken::TypedDeclaration(declaration.clone())); token.type_def = Some(TypeDefinition::TypeId(type_param.type_id)); diff --git a/sway-lsp/src/utils/token.rs b/sway-lsp/src/utils/token.rs index b0ffaade00a..e26162ae400 100644 --- a/sway-lsp/src/utils/token.rs +++ b/sway-lsp/src/utils/token.rs @@ -62,7 +62,9 @@ pub(crate) fn struct_declaration_of_type_id( tokens: &TokenMap, ) -> Option { declaration_of_type_id(type_id, tokens).and_then(|decl| match decl { - TypedDeclaration::StructDeclaration(struct_decl) => Some(struct_decl), + TypedDeclaration::StructDeclaration(ref decl_id) => { + Some(declaration_engine::de_get_struct(decl_id.clone(), &decl.span()).unwrap()) + } _ => None, }) }