Skip to content

Commit

Permalink
Changes struct and enum declarations to contain a call path. (#3900)
Browse files Browse the repository at this point in the history
With these changes `TyStructDeclaration` and `TyEnumDeclaration` now
have a call path instead of a name.

This is required before changing the JSON ABI to use enum and struct
types with call paths instead of only names which can be duplicate.

This also fixes #418 by changing `Unifier` to compare `CallPath`'s
instead of `Ident`'s for enums and structs.

Closes #418

---------

Co-authored-by: João Matos <joao@tritao.eu>
  • Loading branch information
2 people authored and eightfilms committed Feb 7, 2023
1 parent f22b62e commit 1cf01c7
Show file tree
Hide file tree
Showing 43 changed files with 324 additions and 147 deletions.
4 changes: 2 additions & 2 deletions forc-plugins/forc-doc/src/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl Descriptor {
if !document_private_items && struct_decl.visibility.is_private() {
Ok(Descriptor::NonDocumentable)
} else {
let item_name = struct_decl.name;
let item_name = struct_decl.call_path.suffix;
let attrs_opt = (!struct_decl.attributes.is_empty())
.then(|| struct_decl.attributes.to_html_string());
let context = (!struct_decl.fields.is_empty())
Expand Down Expand Up @@ -81,7 +81,7 @@ impl Descriptor {
if !document_private_items && enum_decl.visibility.is_private() {
Ok(Descriptor::NonDocumentable)
} else {
let item_name = enum_decl.name;
let item_name = enum_decl.call_path.suffix;
let attrs_opt = (!enum_decl.attributes.is_empty())
.then(|| enum_decl.attributes.to_html_string());
let context = (!enum_decl.variants.is_empty())
Expand Down
8 changes: 4 additions & 4 deletions sway-core/src/abi_generation/evm_json_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ pub fn json_abi_str(type_info: &TypeInfo, type_engine: &TypeEngine) -> String {
Numeric => "u64".into(), // u64 is the default
Contract => "contract".into(),
ErrorRecovery => "unknown due to error".into(),
Enum { name, .. } => {
format!("enum {name}")
Enum { call_path, .. } => {
format!("enum {}", call_path.suffix)
}
Struct { name, .. } => {
format!("struct {name}")
Struct { call_path, .. } => {
format!("struct {}", call_path.suffix)
}
ContractCaller { abi_name, .. } => {
format!("contract caller {abi_name}")
Expand Down
8 changes: 4 additions & 4 deletions sway-core/src/abi_generation/fuel_json_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,11 +567,11 @@ impl TypeInfo {
Numeric => "u64".into(), // u64 is the default
Contract => "contract".into(),
ErrorRecovery => "unknown due to error".into(),
Enum { name, .. } => {
format!("enum {name}")
Enum { call_path, .. } => {
format!("enum {}", call_path.suffix)
}
Struct { name, .. } => {
format!("struct {name}")
Struct { call_path, .. } => {
format!("struct {}", call_path.suffix)
}
ContractCaller { abi_name, .. } => {
format!("contract caller {abi_name}")
Expand Down
51 changes: 27 additions & 24 deletions sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ fn connect_struct_declaration<'eng: 'cfg, 'cfg>(
tree_type: &TreeType,
) {
let ty::TyStructDeclaration {
name,
call_path,
fields,
visibility,
..
Expand All @@ -478,9 +478,11 @@ fn connect_struct_declaration<'eng: 'cfg, 'cfg>(

// Now, populate the struct namespace with the location of this struct as well as the indexes
// of the field names
graph
.namespace
.insert_struct(name.as_str().to_string(), entry_node, field_nodes);
graph.namespace.insert_struct(
call_path.suffix.as_str().to_string(),
entry_node,
field_nodes,
);
}

/// Implementations of traits are top-level things that are not conditional, so
Expand Down Expand Up @@ -601,10 +603,10 @@ fn connect_abi_declaration(
// be used outside of the contract.
for fn_decl_id in decl.interface_surface.iter() {
let fn_decl = decl_engine.get_trait_fn(fn_decl_id.clone(), &decl.span)?;
if let Some(TypeInfo::Struct { name, .. }) =
if let Some(TypeInfo::Struct { call_path, .. }) =
get_struct_type_info_from_type_id(type_engine, fn_decl.return_type)?
{
if let Some(ns) = graph.namespace.get_struct(&name).cloned() {
if let Some(ns) = graph.namespace.get_struct(&call_path.suffix).cloned() {
for (_, field_ix) in ns.fields.iter() {
graph.add_edge(ns.struct_decl_ix, *field_ix, "".into());
}
Expand Down Expand Up @@ -683,7 +685,7 @@ fn connect_enum_declaration<'eng: 'cfg, 'cfg>(
) {
graph
.namespace
.insert_enum(enum_decl.name.clone(), entry_node);
.insert_enum(enum_decl.call_path.suffix.clone(), entry_node);

// keep a mapping of each variant
for variant in enum_decl.variants.iter() {
Expand All @@ -696,7 +698,7 @@ fn connect_enum_declaration<'eng: 'cfg, 'cfg>(
);

graph.namespace.insert_enum_variant(
enum_decl.name.clone(),
enum_decl.call_path.suffix.clone(),
entry_node,
variant.name.clone(),
variant_index,
Expand Down Expand Up @@ -770,21 +772,22 @@ fn connect_fn_params_struct_enums<'eng: 'cfg, 'cfg>(
for fn_param in &fn_decl.parameters {
let ty = type_engine.to_typeinfo(fn_param.type_id, &fn_param.type_span)?;
match ty {
TypeInfo::Enum { name, .. } => {
let ty_index = match graph.namespace.find_enum(&name) {
TypeInfo::Enum { call_path, .. } => {
let ty_index = match graph.namespace.find_enum(&call_path.suffix) {
Some(ix) => *ix,
None => {
graph.add_node(engines, format!("External enum {}", name.as_str()).into())
}
None => graph.add_node(
engines,
format!("External enum {}", call_path.suffix.as_str()).into(),
),
};
graph.add_edge(fn_decl_entry_node, ty_index, "".into());
}
TypeInfo::Struct { name, .. } => {
let ty_index = match graph.namespace.find_struct_decl(name.as_str()) {
TypeInfo::Struct { call_path, .. } => {
let ty_index = match graph.namespace.find_struct_decl(call_path.suffix.as_str()) {
Some(ix) => *ix,
None => graph.add_node(
engines,
format!("External struct {}", name.as_str()).into(),
format!("External struct {}", call_path.suffix.as_str()).into(),
),
};
graph.add_edge(fn_decl_entry_node, ty_index, "".into());
Expand Down Expand Up @@ -835,7 +838,7 @@ fn get_trait_fn_node_index<'a>(
let struct_decl = decl_engine.get_struct(decl, &expression_span)?;
Ok(graph
.namespace
.find_trait_method(&struct_decl.name.into(), &fn_decl.name))
.find_trait_method(&struct_decl.call_path.suffix.into(), &fn_decl.name))
}
ty::TyDeclaration::ImplTrait(decl) => {
let impl_trait = decl_engine.get_impl_trait(decl, &expression_span)?;
Expand Down Expand Up @@ -1158,14 +1161,14 @@ fn connect_expression<'eng: 'cfg, 'cfg>(

assert!(matches!(resolved_type_of_parent, TypeInfo::Struct { .. }));
let resolved_type_of_parent = match resolved_type_of_parent {
TypeInfo::Struct { name, .. } => name,
TypeInfo::Struct { call_path, .. } => call_path,
_ => panic!("Called subfield on a non-struct"),
};
let field_name = &field_to_access.name;
// find the struct field index in the namespace
let field_ix = match graph
.namespace
.find_struct_field_idx(resolved_type_of_parent.as_str(), field_name.as_str())
.find_struct_field_idx(resolved_type_of_parent.suffix.as_str(), field_name.as_str())
{
Some(ix) => *ix,
None => graph.add_node(engines, "external struct".into()),
Expand Down Expand Up @@ -1563,16 +1566,16 @@ fn connect_enum_instantiation<'eng: 'cfg, 'cfg>(
tree_type: &TreeType,
options: NodeConnectionOptions,
) -> Result<Vec<NodeIndex>, CompileError> {
let enum_name = &enum_decl.name;
let enum_call_path = enum_decl.call_path.clone();
let (decl_ix, variant_index) = graph
.namespace
.find_enum_variant_index(enum_name, variant_name)
.find_enum_variant_index(&enum_call_path.suffix, variant_name)
.unwrap_or_else(|| {
let node_idx = graph.add_node(
engines,
format!(
"extern enum {}::{}",
enum_name.as_str(),
enum_call_path.suffix.as_str(),
variant_name.as_str()
)
.into(),
Expand Down Expand Up @@ -1645,7 +1648,7 @@ fn construct_dead_code_warning_from_node(
span,
} => {
let warning_span = match decl_engine.get_struct(decl_id.clone(), span) {
Ok(ty::TyStructDeclaration { name, .. }) => name.span(),
Ok(ty::TyStructDeclaration { call_path, .. }) => call_path.span(),
Err(_) => span.clone(),
};
CompileWarning {
Expand All @@ -1658,7 +1661,7 @@ fn construct_dead_code_warning_from_node(
span,
} => {
let warning_span = match decl_engine.get_enum(decl_id.clone(), span) {
Ok(ty::TyEnumDeclaration { name, .. }) => name.span(),
Ok(ty::TyEnumDeclaration { call_path, .. }) => call_path.span(),
Err(_) => span.clone(),
};
CompileWarning {
Expand Down
12 changes: 8 additions & 4 deletions sway-core/src/ir_generation/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@ pub(super) fn get_struct_name_field_index_and_type(
.ok()?;
match (ty_info, field_kind) {
(
TypeInfo::Struct { name, fields, .. },
TypeInfo::Struct {
call_path, fields, ..
},
ty::ProjectionKind::StructField { name: field_name },
) => Some((
name.as_str().to_owned(),
call_path.suffix.as_str().to_owned(),
fields
.iter()
.enumerate()
Expand Down Expand Up @@ -149,7 +151,9 @@ pub(super) fn get_indices_for_struct_access(
// Get the field index and also its type for the next iteration.
match (ty_info, &field_kind) {
(
TypeInfo::Struct { name, fields, .. },
TypeInfo::Struct {
call_path, fields, ..
},
ty::ProjectionKind::StructField { name: field_name },
) => {
let field_idx_and_type_opt = fields
Expand All @@ -163,7 +167,7 @@ pub(super) fn get_indices_for_struct_access(
format!(
"Unknown field '{}' for struct {} in reassignment.",
field_kind.pretty_print(),
name,
call_path,
),
field_kind.span(),
));
Expand Down
16 changes: 12 additions & 4 deletions sway-core/src/language/call_path.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::fmt;
use std::{fmt, sync::Arc};

use crate::{Ident, Namespace};

Expand Down Expand Up @@ -45,13 +45,21 @@ impl<T: Spanned> Spanned for CallPath<T> {
if self.prefixes.is_empty() {
self.suffix.span()
} else {
let prefixes_spans = self
let mut prefixes_spans = self
.prefixes
.iter()
.map(|x| x.span())
//LOC below should be removed when #21 goes in
.filter(|x| x.path() == self.suffix.span().path());
Span::join(Span::join_all(prefixes_spans), self.suffix.span())
.filter(|x| {
Arc::ptr_eq(x.src(), self.suffix.span().src())
&& x.path() == self.suffix.span().path()
})
.peekable();
if prefixes_spans.peek().is_some() {
Span::join(Span::join_all(prefixes_spans), self.suffix.span())
} else {
self.suffix.span()
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions sway-core/src/language/parsed/expression/scrutinee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub enum Scrutinee {
span: Span,
},
StructScrutinee {
struct_name: Ident,
struct_name: CallPath,
fields: Vec<StructScrutineeField>,
span: Span,
},
Expand Down Expand Up @@ -131,7 +131,7 @@ impl Scrutinee {
..
} => {
let name = vec![TypeInfo::Custom {
name: struct_name.clone(),
name: struct_name.clone().suffix,
type_arguments: None,
}];
let fields = fields
Expand Down
12 changes: 8 additions & 4 deletions sway-core/src/language/ty/declaration/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,15 @@ impl DisplayWithEngines for TyDeclaration {
}
TyDeclaration::StructDeclaration(decl_id) => {
match decl_engine.get_struct(decl_id.clone(), &decl_id.span()) {
Ok(TyStructDeclaration { name, .. }) => name.as_str().into(),
Ok(TyStructDeclaration { call_path, .. }) => {
call_path.suffix.as_str().into()
}
Err(_) => "unknown struct".into(),
}
}
TyDeclaration::EnumDeclaration(decl_id) => {
match decl_engine.get_enum(decl_id.clone(), &decl_id.span()) {
Ok(TyEnumDeclaration { name, .. }) => name.as_str().into(),
Ok(TyEnumDeclaration { call_path, .. }) => call_path.suffix.as_str().into(),
Err(_) => "unknown enum".into(),
}
}
Expand Down Expand Up @@ -281,13 +283,15 @@ impl GetDeclIdent for TyDeclaration {
decl_engine
.get_struct(decl.clone(), &decl.span())
.unwrap()
.name,
.call_path
.suffix,
),
TyDeclaration::EnumDeclaration(decl) => Some(
decl_engine
.get_enum(decl.clone(), &decl.span())
.unwrap()
.name,
.call_path
.suffix,
),
TyDeclaration::ImplTrait(decl) => Some(
decl_engine
Expand Down
18 changes: 12 additions & 6 deletions sway-core/src/language/ty/declaration/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ use std::hash::{Hash, Hasher};
use sway_error::error::CompileError;
use sway_types::{Ident, Span, Spanned};

use crate::{engine_threading::*, error::*, language::Visibility, transform, type_system::*};
use crate::{
engine_threading::*,
error::*,
language::{CallPath, Visibility},
transform,
type_system::*,
};

#[derive(Clone, Debug)]
pub struct TyEnumDeclaration {
pub name: Ident,
pub call_path: CallPath,
pub type_parameters: Vec<TypeParameter>,
pub attributes: transform::AttributesMap,
pub variants: Vec<TyEnumVariant>,
Expand All @@ -21,7 +27,7 @@ pub struct TyEnumDeclaration {
impl EqWithEngines for TyEnumDeclaration {}
impl PartialEqWithEngines for TyEnumDeclaration {
fn eq(&self, other: &Self, engines: Engines<'_>) -> bool {
self.name == other.name
self.call_path.suffix == other.call_path.suffix
&& self.type_parameters.eq(&other.type_parameters, engines)
&& self.variants.eq(&other.variants, engines)
&& self.visibility == other.visibility
Expand Down Expand Up @@ -57,7 +63,7 @@ impl CreateTypeId for TyEnumDeclaration {
type_engine.insert(
decl_engine,
TypeInfo::Enum {
name: self.name.clone(),
call_path: self.call_path.clone(),
variant_types: self.variants.clone(),
type_parameters: self.type_parameters.clone(),
},
Expand All @@ -77,7 +83,7 @@ impl MonomorphizeHelper for TyEnumDeclaration {
}

fn name(&self) -> &Ident {
&self.name
&self.call_path.suffix
}
}

Expand All @@ -96,7 +102,7 @@ impl TyEnumDeclaration {
Some(variant) => ok(variant, warnings, errors),
None => {
errors.push(CompileError::UnknownEnumVariant {
enum_name: self.name.clone(),
enum_name: self.call_path.suffix.clone(),
variant_name: variant_name.clone(),
span: variant_name.span(),
});
Expand Down
Loading

0 comments on commit 1cf01c7

Please sign in to comment.