Skip to content

Commit

Permalink
Implement parsing and semantic analysis for associated consts (FuelLa…
Browse files Browse the repository at this point in the history
…bs#4262)

## Description

This splits off the parsing and semantic analysis changes out of
FuelLabs#4036 into a bunch of commits:

[Implement associated constants in traits and
ABIs.](FuelLabs@c333b4d)

[Added multiple definition error name checking to
traits.](FuelLabs@88dc9d1)

[Refactor namespace method resolving code to be
item-based.](FuelLabs@5d2eb6f)

[Add constants to the trait namespace and map to allow referencing from
methods](FuelLabs@d4c48f7)

This one adds a bunch of disabled tests, next PR will enable them with
corresponding IR generation changes and docs.

Related to FuelLabs#3797.

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
  • Loading branch information
tritao authored Mar 15, 2023
1 parent 1a2d323 commit ee0a0fd
Show file tree
Hide file tree
Showing 88 changed files with 1,281 additions and 215 deletions.
2 changes: 2 additions & 0 deletions forc-plugins/forc-doc/src/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ impl Descriptor {
.into_iter()
.flat_map(|item| match item {
TyTraitInterfaceItem::TraitFn(fn_decl) => Some(fn_decl),
_ => None,
})
.collect::<Vec<_>>()
.to_methods(decl_engine),
Expand Down Expand Up @@ -170,6 +171,7 @@ impl Descriptor {
.into_iter()
.flat_map(|item| match item {
TyTraitInterfaceItem::TraitFn(fn_decl) => Some(fn_decl),
_ => None,
})
.collect::<Vec<_>>()
.to_methods(decl_engine),
Expand Down
2 changes: 2 additions & 0 deletions sway-ast/src/item/item_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::priv_prelude::*;
#[derive(Clone, Debug, Serialize)]
pub enum ItemImplItem {
Fn(ItemFn),
Const(ItemConst),
}

#[derive(Clone, Debug, Serialize)]
Expand All @@ -25,6 +26,7 @@ impl Spanned for ItemImplItem {
fn span(&self) -> Span {
match self {
ItemImplItem::Fn(fn_decl) => fn_decl.span(),
ItemImplItem::Const(const_decl) => const_decl.span(),
}
}
}
2 changes: 2 additions & 0 deletions sway-ast/src/item/item_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::priv_prelude::*;
#[derive(Clone, Debug, Serialize)]
pub enum ItemTraitItem {
Fn(FnSignature),
Const(ItemConst),
}

#[derive(Clone, Debug, Serialize)]
Expand Down Expand Up @@ -35,6 +36,7 @@ impl Spanned for ItemTraitItem {
fn span(&self) -> Span {
match self {
ItemTraitItem::Fn(fn_decl) => fn_decl.span(),
ItemTraitItem::Const(const_decl) => const_decl.span(),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ fn connect_impl_trait<'eng: 'cfg, 'cfg>(
connect_typed_fn_decl(engines, &fn_decl, graph, fn_decl_entry_node)?;
methods_and_indexes.push((fn_decl.name.clone(), fn_decl_entry_node));
}
TyImplItem::Constant(_const_decl) => {}
}
}
// Now, insert the methods into the trait method namespace.
Expand Down
2 changes: 2 additions & 0 deletions sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ fn connect_impl_trait<'eng: 'cfg, 'cfg>(
)?;
methods_and_indexes.push((fn_decl.name.clone(), fn_decl_entry_node));
}
TyImplItem::Constant(_const_decl) => {}
}
}
// we also want to add an edge from the methods back to the trait, so if a method gets called,
Expand Down Expand Up @@ -607,6 +608,7 @@ fn connect_abi_declaration(
}
}
}
ty::TyTraitInterfaceItem::Constant(_) => todo!(),
}
}

Expand Down
28 changes: 28 additions & 0 deletions sway-core/src/decl_engine/functional_decl_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::{
pub enum FunctionalDeclId {
TraitFn(DeclId<ty::TyTraitFn>),
Function(DeclId<ty::TyFunctionDeclaration>),
Constant(DeclId<ty::TyConstantDeclaration>),
}

impl From<DeclId<ty::TyFunctionDeclaration>> for FunctionalDeclId {
Expand Down Expand Up @@ -44,6 +45,22 @@ impl From<&mut DeclId<ty::TyTraitFn>> for FunctionalDeclId {
}
}

impl From<DeclId<ty::TyConstantDeclaration>> for FunctionalDeclId {
fn from(val: DeclId<ty::TyConstantDeclaration>) -> Self {
Self::Constant(val)
}
}
impl From<&DeclId<ty::TyConstantDeclaration>> for FunctionalDeclId {
fn from(val: &DeclId<ty::TyConstantDeclaration>) -> Self {
Self::Constant(*val)
}
}
impl From<&mut DeclId<ty::TyConstantDeclaration>> for FunctionalDeclId {
fn from(val: &mut DeclId<ty::TyConstantDeclaration>) -> Self {
Self::Constant(*val)
}
}

impl std::fmt::Display for FunctionalDeclId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand All @@ -53,6 +70,9 @@ impl std::fmt::Display for FunctionalDeclId {
Self::Function(_) => {
write!(f, "decl(function)",)
}
Self::Constant(_) => {
write!(f, "decl(constant)",)
}
}
}
}
Expand All @@ -70,6 +90,10 @@ impl TryFrom<DeclRefMixedFunctional> for DeclRefFunction {
actually: actually.to_string(),
span: value.decl_span().clone(),
}),
actually @ FunctionalDeclId::Constant(_) => Err(CompileError::DeclIsNotAFunction {
actually: actually.to_string(),
span: value.decl_span().clone(),
}),
}
}
}
Expand All @@ -89,6 +113,10 @@ impl TryFrom<FunctionalDeclId> for DeclId<TyFunctionDeclaration> {
actually: actually.to_string(),
span: Span::dummy(), // FIXME
}),
actually @ FunctionalDeclId::Constant(_) => Err(CompileError::DeclIsNotAFunction {
actually: actually.to_string(),
span: Span::dummy(), // FIXME
}),
}
}
}
Expand Down
38 changes: 23 additions & 15 deletions sway-core/src/decl_engine/mapping.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::fmt;

use crate::language::ty::{TyFunctionDeclaration, TyTraitInterfaceItem, TyTraitItem};
use crate::language::ty::{TyTraitInterfaceItem, TyTraitItem};

use super::{DeclId, FunctionalDeclId, InterfaceItemMap, ItemMap};
use super::{FunctionalDeclId, InterfaceItemMap, ItemMap};

type SourceDecl = FunctionalDeclId;
type DestinationDecl = DeclId<TyFunctionDeclaration>;
type DestinationDecl = FunctionalDeclId;

/// The [DeclMapping] is used to create a mapping between a [SourceDecl] (LHS)
/// and a [DestinationDecl] (RHS).
Expand All @@ -21,7 +21,15 @@ impl fmt::Display for DeclMapping {
self.mapping
.iter()
.map(|(source_type, dest_type)| {
format!("{} -> {}", source_type, dest_type.inner(),)
format!(
"{} -> {}",
source_type,
match dest_type {
FunctionalDeclId::TraitFn(decl_id) => decl_id.inner(),
FunctionalDeclId::Function(decl_id) => decl_id.inner(),
FunctionalDeclId::Constant(decl_id) => decl_id.inner(),
}
)
})
.collect::<Vec<_>>()
.join(", ")
Expand Down Expand Up @@ -56,28 +64,28 @@ impl DeclMapping {
let mut mapping: Vec<(SourceDecl, DestinationDecl)> = vec![];
for (interface_decl_name, interface_item) in interface_decl_refs.into_iter() {
if let Some(new_item) = impld_decl_refs.get(&interface_decl_name) {
#[allow(clippy::infallible_destructuring_match)]
let interface_decl_ref = match interface_item {
TyTraitInterfaceItem::TraitFn(decl_ref) => decl_ref,
TyTraitInterfaceItem::TraitFn(decl_ref) => decl_ref.id().into(),
TyTraitInterfaceItem::Constant(decl_ref) => decl_ref.id().into(),
};
#[allow(clippy::infallible_destructuring_match)]
let new_decl_ref = match new_item {
TyTraitItem::Fn(decl_ref) => decl_ref,
TyTraitItem::Fn(decl_ref) => decl_ref.id().into(),
TyTraitItem::Constant(decl_ref) => decl_ref.id().into(),
};
mapping.push(((*interface_decl_ref.id()).into(), *new_decl_ref.id()));
mapping.push((interface_decl_ref, new_decl_ref));
}
}
for (decl_name, item) in item_decl_refs.into_iter() {
if let Some(new_item) = impld_decl_refs.get(&decl_name) {
#[allow(clippy::infallible_destructuring_match)]
let interface_decl_ref = match item {
TyTraitItem::Fn(decl_ref) => decl_ref,
TyTraitItem::Fn(decl_ref) => decl_ref.id().into(),
TyTraitItem::Constant(decl_ref) => decl_ref.id().into(),
};
#[allow(clippy::infallible_destructuring_match)]
let new_decl_ref = match new_item {
TyTraitItem::Fn(decl_ref) => decl_ref,
TyTraitItem::Fn(decl_ref) => decl_ref.id().into(),
TyTraitItem::Constant(decl_ref) => decl_ref.id().into(),
};
mapping.push(((*interface_decl_ref.id()).into(), new_decl_ref.into()));
mapping.push((interface_decl_ref, new_decl_ref));
}
}
DeclMapping { mapping }
Expand All @@ -86,7 +94,7 @@ impl DeclMapping {
pub(crate) fn find_match(&self, decl_ref: SourceDecl) -> Option<DestinationDecl> {
for (source_decl_ref, dest_decl_ref) in self.mapping.iter() {
if *source_decl_ref == decl_ref {
return Some(*dest_decl_ref);
return Some(dest_decl_ref.clone());
}
}
None
Expand Down
8 changes: 6 additions & 2 deletions sway-core/src/decl_engine/ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,13 +333,17 @@ impl ReplaceDecls for DeclRefFunction {
fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, engines: Engines<'_>) {
let decl_engine = engines.de();
if let Some(new_decl_ref) = decl_mapping.find_match(self.id.into()) {
self.id = new_decl_ref;
if let FunctionalDeclId::Function(new_decl_ref) = new_decl_ref {
self.id = new_decl_ref;
}
return;
}
let all_parents = decl_engine.find_all_parents(engines, &self.id);
for parent in all_parents.iter() {
if let Some(new_decl_ref) = decl_mapping.find_match(parent.clone()) {
self.id = new_decl_ref;
if let FunctionalDeclId::Function(new_decl_ref) = new_decl_ref {
self.id = new_decl_ref;
}
return;
}
}
Expand Down
5 changes: 3 additions & 2 deletions sway-core/src/language/parsed/declaration/impl_trait.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use super::FunctionDeclaration;
use crate::{language::CallPath, type_system::TypeParameter, TypeArgument};
use super::{ConstantDeclaration, FunctionDeclaration};
use crate::{language::CallPath, type_system::TypeArgument, TypeParameter};

use sway_types::span::Span;

#[derive(Debug, Clone)]
pub enum ImplItem {
Fn(FunctionDeclaration),
Constant(ConstantDeclaration),
}

#[derive(Debug, Clone)]
Expand Down
3 changes: 2 additions & 1 deletion sway-core/src/language/parsed/declaration/trait.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::hash::{Hash, Hasher};

use super::{FunctionDeclaration, FunctionParameter};
use super::{ConstantDeclaration, FunctionDeclaration, FunctionParameter};

use crate::{
decl_engine::DeclRefTrait, engine_threading::*, language::*, transform, type_system::*,
Expand All @@ -10,6 +10,7 @@ use sway_types::{ident::Ident, span::Span, Spanned};
#[derive(Debug, Clone)]
pub enum TraitItem {
TraitFn(TraitFn),
Constant(ConstantDeclaration),
}

#[derive(Debug, Clone)]
Expand Down
46 changes: 46 additions & 0 deletions sway-core/src/language/ty/declaration/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::hash::{Hash, Hasher};
use sway_types::{Ident, Named, Span, Spanned};

use crate::{
decl_engine::{DeclMapping, ReplaceDecls},
engine_threading::*,
language::{ty::*, CallPath, Visibility},
transform,
Expand All @@ -16,29 +17,42 @@ pub struct TyConstantDeclaration {
pub visibility: Visibility,
pub is_configurable: bool,
pub attributes: transform::AttributesMap,
pub return_type: TypeId,
pub type_ascription: TypeArgument,
pub span: Span,
pub implementing_type: Option<TyDeclaration>,
}

impl EqWithEngines for TyConstantDeclaration {}
impl PartialEqWithEngines for TyConstantDeclaration {
fn eq(&self, other: &Self, engines: Engines<'_>) -> bool {
let type_engine = engines.te();
self.call_path == other.call_path
&& self.value.eq(&other.value, engines)
&& self.visibility == other.visibility
&& self.type_ascription.eq(&other.type_ascription, engines)
&& self.is_configurable == other.is_configurable
&& type_engine
.get(self.return_type)
.eq(&type_engine.get(other.return_type), engines)
&& match (&self.implementing_type, &other.implementing_type) {
(Some(self_), Some(other)) => self_.eq(other, engines),
_ => false,
}
}
}

impl HashWithEngines for TyConstantDeclaration {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
let type_engine = engines.te();
let TyConstantDeclaration {
call_path,
value,
visibility,
return_type,
type_ascription,
is_configurable,
implementing_type,
// these fields are not hashed because they aren't relevant/a
// reliable source of obj v. obj distinction
attributes: _,
Expand All @@ -47,8 +61,12 @@ impl HashWithEngines for TyConstantDeclaration {
call_path.hash(state);
value.hash(state, engines);
visibility.hash(state);
type_engine.get(*return_type).hash(state, engines);
type_ascription.hash(state, engines);
is_configurable.hash(state);
if let Some(implementing_type) = implementing_type {
(*implementing_type).hash(state, engines);
}
}
}

Expand All @@ -63,3 +81,31 @@ impl Spanned for TyConstantDeclaration {
self.span.clone()
}
}

impl SubstTypes for TyConstantDeclaration {
fn subst_inner(&mut self, type_mapping: &TypeSubstMap, engines: Engines<'_>) {
self.return_type.subst(type_mapping, engines);
self.type_ascription.subst(type_mapping, engines);
if let Some(expr) = &mut self.value {
expr.subst(type_mapping, engines);
}
}
}

impl ReplaceSelfType for TyConstantDeclaration {
fn replace_self_type(&mut self, engines: Engines<'_>, self_type: TypeId) {
self.return_type.replace_self_type(engines, self_type);
self.type_ascription.replace_self_type(engines, self_type);
if let Some(expr) = &mut self.value {
expr.replace_self_type(engines, self_type);
}
}
}

impl ReplaceDecls for TyConstantDeclaration {
fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, engines: Engines<'_>) {
if let Some(expr) = &mut self.value {
expr.replace_decls(decl_mapping, engines);
}
}
}
Loading

0 comments on commit ee0a0fd

Please sign in to comment.