Skip to content

Commit

Permalink
Introduce a new symbol resolving pass (#5809)
Browse files Browse the repository at this point in the history
## Description

This PR implements a new AST resolution approach that resolves symbols
using the information from the collection context.

To achieve this, we introduce a new `ResolveSymbols` trait and
`SymbolResolveContext` context type.

Parsed nodes now contain a `resolved_call_path_binding:
Option<TypeBinding<ResolvedCallPath<ParsedDeclId<...>>>>`, which contain
the resolved call path binding that references the `ParsedDeclId`
relative to the resolved name. This field is resolved by the new
`resolve_symbols` pass, which mutates the `resolved_call_path_binding`
as it walks through the nodes.

Most of the name lookups are implemented in the new
`SymbolResolveTypeBinding` which is equivalent to the existing
`TypeCheckTypeBinding` (to be removed once everything is migrated in the
type checker).

The only exception right now are `DelineatedPath` and
`AmbiguousPathExpression` which are not being fully resolved yet (though
there is a draft PR right now with some of this ongoing work).

Also to note there are a handful of unused functions in the context that
will be used in the next PRs.

These are the main commits:

[Implement
Declaration::TraitFn.](8da3223)

[Implement decl_engine_parsed_decl and
get_parsed_decl.](dd6f5e6)

[Fix lexical scope id calculation on
creation.](e16d996)

[Add symbol resolve
context.](e9356cc)

[Collect nodes inside each function body and keep a reference to their
lexical
scope](e327345)

[Resolve alias declarations when resolving struct
symbols.](2c8dc64)

Partially closes #5379.

## 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] If my change requires substantial documentation changes, I have
[requested support from the DevRel
team](https://github.com/FuelLabs/devrel-requests/issues/new/choose)
- [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 committed Aug 6, 2024
1 parent 68b7b34 commit 159f049
Show file tree
Hide file tree
Showing 40 changed files with 1,438 additions and 54 deletions.
90 changes: 87 additions & 3 deletions sway-core/src/decl_engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ use crate::{
engine_threading::*,
language::{
parsed::{
AbiDeclaration, ConfigurableDeclaration, ConstantDeclaration, EnumDeclaration,
FunctionDeclaration, ImplSelfOrTrait, StorageDeclaration, StructDeclaration,
TraitDeclaration, TraitFn, TraitTypeDeclaration, TypeAliasDeclaration,
AbiDeclaration, ConfigurableDeclaration, ConstantDeclaration, Declaration,
EnumDeclaration, FunctionDeclaration, ImplSelfOrTrait, StorageDeclaration,
StructDeclaration, TraitDeclaration, TraitFn, TraitTypeDeclaration,
TypeAliasDeclaration,
},
ty::{
self, TyAbiDecl, TyConfigurableDecl, TyConstantDecl, TyDeclParsedType, TyEnumDecl,
Expand Down Expand Up @@ -122,6 +123,13 @@ where
fn get_parsed_decl_id(&self, decl_id: &DeclId<T>) -> Option<ParsedDeclId<T::ParsedType>>;
}

pub trait DeclEngineGetParsedDecl<T>
where
T: TyDeclParsedType,
{
fn get_parsed_decl(&self, decl_id: &DeclId<T>) -> Option<Declaration>;
}

pub trait DeclEngineInsert<T>
where
T: Named + Spanned + TyDeclParsedType,
Expand Down Expand Up @@ -288,6 +296,82 @@ decl_engine_parsed_decl_id!(configurable_parsed_decl_id_map, ty::TyConfigurableD
decl_engine_parsed_decl_id!(enum_parsed_decl_id_map, ty::TyEnumDecl);
decl_engine_parsed_decl_id!(type_alias_parsed_decl_id_map, ty::TyTypeAliasDecl);

macro_rules! decl_engine_parsed_decl {
($slab:ident, $decl:ty, $ctor:expr) => {
impl DeclEngineGetParsedDecl<$decl> for DeclEngine {
fn get_parsed_decl(&self, decl_id: &DeclId<$decl>) -> Option<Declaration> {
let parsed_decl_id_map = self.$slab.read();
if let Some(parsed_decl_id) = parsed_decl_id_map.get(&decl_id) {
return Some($ctor(parsed_decl_id.clone()));
} else {
None
}
}
}
};
}

decl_engine_parsed_decl!(
function_parsed_decl_id_map,
ty::TyFunctionDecl,
Declaration::FunctionDeclaration
);
decl_engine_parsed_decl!(
trait_parsed_decl_id_map,
ty::TyTraitDecl,
Declaration::TraitDeclaration
);
decl_engine_parsed_decl!(
trait_fn_parsed_decl_id_map,
ty::TyTraitFn,
Declaration::TraitFnDeclaration
);
decl_engine_parsed_decl!(
trait_type_parsed_decl_id_map,
ty::TyTraitType,
Declaration::TraitTypeDeclaration
);
decl_engine_parsed_decl!(
impl_self_or_trait_parsed_decl_id_map,
ty::TyImplSelfOrTrait,
Declaration::ImplSelfOrTrait
);
decl_engine_parsed_decl!(
struct_parsed_decl_id_map,
ty::TyStructDecl,
Declaration::StructDeclaration
);
decl_engine_parsed_decl!(
storage_parsed_decl_id_map,
ty::TyStorageDecl,
Declaration::StorageDeclaration
);
decl_engine_parsed_decl!(
abi_parsed_decl_id_map,
ty::TyAbiDecl,
Declaration::AbiDeclaration
);
decl_engine_parsed_decl!(
constant_parsed_decl_id_map,
ty::TyConstantDecl,
Declaration::ConstantDeclaration
);
decl_engine_parsed_decl!(
configurable_parsed_decl_id_map,
ty::TyConfigurableDecl,
Declaration::ConfigurableDeclaration
);
decl_engine_parsed_decl!(
enum_parsed_decl_id_map,
ty::TyEnumDecl,
Declaration::EnumDeclaration
);
decl_engine_parsed_decl!(
type_alias_parsed_decl_id_map,
ty::TyTypeAliasDecl,
Declaration::TypeAliasDeclaration
);

macro_rules! decl_engine_replace {
($slab:ident, $decl:ty) => {
impl DeclEngineReplace<$decl> for DeclEngine {
Expand Down
24 changes: 24 additions & 0 deletions sway-core/src/decl_engine/parsed_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,30 @@ decl_engine_insert!(enum_slab, EnumDeclaration);
decl_engine_insert!(enum_variant_slab, EnumVariant);
decl_engine_insert!(type_alias_slab, TypeAliasDeclaration);

macro_rules! decl_engine_replace {
($slab:ident, $decl:ty) => {
impl ParsedDeclEngineReplace<$decl> for ParsedDeclEngine {
fn replace(&self, index: ParsedDeclId<$decl>, decl: $decl) {
self.$slab.replace(index.inner(), decl);
}
}
};
}

decl_engine_replace!(variable_slab, VariableDeclaration);
decl_engine_replace!(function_slab, FunctionDeclaration);
decl_engine_replace!(trait_slab, TraitDeclaration);
decl_engine_replace!(trait_fn_slab, TraitFn);
decl_engine_replace!(trait_type_slab, TraitTypeDeclaration);
decl_engine_replace!(impl_self_or_trait_slab, ImplSelfOrTrait);
decl_engine_replace!(struct_slab, StructDeclaration);
decl_engine_replace!(storage_slab, StorageDeclaration);
decl_engine_replace!(abi_slab, AbiDeclaration);
decl_engine_replace!(configurable_slab, ConfigurableDeclaration);
decl_engine_replace!(constant_slab, ConstantDeclaration);
decl_engine_replace!(enum_slab, EnumDeclaration);
decl_engine_replace!(type_alias_slab, TypeAliasDeclaration);

macro_rules! decl_engine_clear {
($($slab:ident, $decl:ty);* $(;)?) => {
impl ParsedDeclEngine {
Expand Down
6 changes: 6 additions & 0 deletions sway-core/src/language/call_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ impl<T: OrdWithEngines> OrdWithEngines for CallPath<T> {
}
}

#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct ResolvedCallPath<T, U = Ident> {
pub decl: T,
pub unresolved_call_path: CallPath<U>,
}

impl std::convert::From<Ident> for CallPath {
fn from(other: Ident) -> Self {
CallPath {
Expand Down
56 changes: 55 additions & 1 deletion sway-core/src/language/parsed/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ pub use r#enum::*;
pub use r#struct::*;
pub use r#trait::*;
pub use storage::*;
use sway_error::{
error::CompileError,
handler::{ErrorEmitted, Handler},
};
use sway_types::{Ident, Span, Spanned};
pub use type_alias::*;
pub use variable::*;
Expand All @@ -29,6 +33,7 @@ use crate::{
decl_engine::{
parsed_engine::{ParsedDeclEngine, ParsedDeclEngineGet},
parsed_id::ParsedDeclId,
DeclEngineGetParsedDeclId,
},
engine_threading::{
DebugWithEngines, DisplayWithEngines, EqWithEngines, PartialEqWithEngines,
Expand All @@ -53,6 +58,7 @@ pub enum Declaration {
StorageDeclaration(ParsedDeclId<StorageDeclaration>),
TypeAliasDeclaration(ParsedDeclId<TypeAliasDeclaration>),
TraitTypeDeclaration(ParsedDeclId<TraitTypeDeclaration>),
TraitFnDeclaration(ParsedDeclId<TraitFn>),
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -84,6 +90,7 @@ impl Declaration {
TraitTypeDeclaration(_) => "type",
FunctionDeclaration(_) => "function",
TraitDeclaration(_) => "trait",
TraitFnDeclaration(_) => "trait fn",
StructDeclaration(_) => "struct",
EnumDeclaration(_) => "enum",
EnumVariantDeclaration(_) => "enum variant",
Expand Down Expand Up @@ -111,9 +118,55 @@ impl Declaration {
StorageDeclaration(decl_id) => pe.get_storage(decl_id).span(),
TypeAliasDeclaration(decl_id) => pe.get_type_alias(decl_id).span(),
TraitTypeDeclaration(decl_id) => pe.get_trait_type(decl_id).span(),
TraitFnDeclaration(decl_id) => pe.get_trait_fn(decl_id).span(),
}
}

pub(crate) fn to_fn_ref(
&self,
handler: &Handler,
engines: &Engines,
) -> Result<ParsedDeclId<FunctionDeclaration>, ErrorEmitted> {
match self {
Declaration::FunctionDeclaration(decl_id) => Ok(*decl_id),
decl => Err(handler.emit_err(CompileError::DeclIsNotAFunction {
actually: decl.friendly_type_name().to_string(),
span: decl.span(engines),
})),
}
}

pub(crate) fn to_struct_decl(
&self,
handler: &Handler,
engines: &Engines,
) -> Result<ParsedDeclId<StructDeclaration>, ErrorEmitted> {
match self {
Declaration::StructDeclaration(decl_id) => Ok(*decl_id),
Declaration::TypeAliasDeclaration(decl_id) => {
let alias = engines.pe().get_type_alias(decl_id);
let struct_decl_id = engines.te().get(alias.ty.type_id).expect_struct(
handler,
engines,
&self.span(engines),
)?;

let parsed_decl_id = engines.de().get_parsed_decl_id(&struct_decl_id);
parsed_decl_id.ok_or_else(|| {
handler.emit_err(CompileError::InternalOwned(
"Cannot get parsed decl id from decl id".to_string(),
self.span(engines),
))
})
}
decl => Err(handler.emit_err(CompileError::DeclIsNotAStruct {
actually: decl.friendly_type_name().to_string(),
span: decl.span(engines),
})),
}
}

#[allow(unused)]
pub(crate) fn visibility(&self, decl_engine: &ParsedDeclEngine) -> Visibility {
match self {
Declaration::TraitDeclaration(decl_id) => decl_engine.get_trait(decl_id).visibility,
Expand All @@ -138,7 +191,8 @@ impl Declaration {
Declaration::ImplSelfOrTrait(_)
| Declaration::StorageDeclaration(_)
| Declaration::AbiDeclaration(_)
| Declaration::TraitTypeDeclaration(_) => Visibility::Public,
| Declaration::TraitTypeDeclaration(_)
| Declaration::TraitFnDeclaration(_) => Visibility::Public,
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions sway-core/src/language/parsed/declaration/function.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
engine_threading::*,
language::{parsed::*, *},
namespace::LexicalScopeId,
transform::{self, AttributeKind},
type_system::*,
};
Expand All @@ -27,6 +28,8 @@ pub struct FunctionDeclaration {
pub type_parameters: Vec<TypeParameter>,
pub where_clause: Vec<(Ident, Vec<TraitConstraint>)>,
pub kind: FunctionDeclarationKind,
pub implementing_type: Option<Declaration>,
pub lexical_scope: LexicalScopeId,
}

impl EqWithEngines for FunctionDeclaration {}
Expand Down
3 changes: 2 additions & 1 deletion sway-core/src/language/parsed/declaration/impl_trait.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{ConstantDeclaration, FunctionDeclaration, TraitTypeDeclaration};
use crate::{
decl_engine::parsed_id::ParsedDeclId,
decl_engine::{parsed_id::ParsedDeclId, ParsedInterfaceDeclId},
engine_threading::{
DebugWithEngines, EqWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext,
},
Expand Down Expand Up @@ -69,6 +69,7 @@ pub struct ImplSelfOrTrait {
pub impl_type_parameters: Vec<TypeParameter>,
pub trait_name: CallPath,
pub trait_type_arguments: Vec<TypeArgument>,
pub trait_decl_ref: Option<ParsedInterfaceDeclId>,
pub implementing_for: TypeArgument,
pub items: Vec<ImplItem>,
// the span of the whole impl trait and block
Expand Down
6 changes: 6 additions & 0 deletions sway-core/src/language/parsed/declaration/trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ pub struct TraitFn {
pub return_type: TypeArgument,
}

impl Spanned for TraitFn {
fn span(&self) -> sway_types::Span {
self.span.clone()
}
}

#[derive(Debug, Clone)]
pub struct TraitTypeDeclaration {
pub name: Ident,
Expand Down
7 changes: 7 additions & 0 deletions sway-core/src/language/parsed/expression/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{cmp::Ordering, fmt, hash::Hasher};

use crate::{
decl_engine::parsed_id::ParsedDeclId,
engine_threading::{
DebugWithEngines, DisplayWithEngines, EqWithEngines, HashWithEngines, OrdWithEngines,
OrdWithEnginesContext, PartialEqWithEngines, PartialEqWithEnginesContext,
Expand All @@ -22,6 +23,8 @@ pub use method_name::MethodName;
pub use scrutinee::*;
use sway_ast::intrinsics::Intrinsic;

use super::{FunctionDeclaration, StructDeclaration};

/// Represents a parsed, but not yet type checked, [Expression](https://en.wikipedia.org/wiki/Expression_(computer_science)).
#[derive(Debug, Clone)]
pub struct Expression {
Expand All @@ -32,6 +35,8 @@ pub struct Expression {
#[derive(Debug, Clone)]
pub struct FunctionApplicationExpression {
pub call_path_binding: TypeBinding<CallPath>,
pub resolved_call_path_binding:
Option<TypeBinding<ResolvedCallPath<ParsedDeclId<FunctionDeclaration>>>>,
pub arguments: Vec<Expression>,
}

Expand Down Expand Up @@ -88,6 +93,8 @@ impl PartialEqWithEngines for ArrayExpression {

#[derive(Debug, Clone)]
pub struct StructExpression {
pub resolved_call_path_binding:
Option<TypeBinding<ResolvedCallPath<ParsedDeclId<StructDeclaration>>>>,
pub call_path_binding: TypeBinding<CallPath>,
pub fields: Vec<StructExpressionField>,
}
Expand Down
24 changes: 22 additions & 2 deletions sway-core/src/language/ty/declaration/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use sway_types::{Ident, Named, Span, Spanned};
use crate::{
decl_engine::*,
engine_threading::*,
language::{ty::*, Visibility},
language::{parsed::Declaration, ty::*, Visibility},
type_system::*,
types::*,
};
Expand Down Expand Up @@ -496,6 +496,26 @@ impl GetDeclIdent for TyDecl {
}

impl TyDecl {
pub(crate) fn get_parsed_decl(&self, decl_engine: &DeclEngine) -> Option<Declaration> {
match self {
TyDecl::VariableDecl(_decl) => None,
TyDecl::ConstantDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id),
TyDecl::ConfigurableDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id),
TyDecl::TraitTypeDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id),
TyDecl::FunctionDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id),
TyDecl::TraitDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id),
TyDecl::StructDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id),
TyDecl::EnumDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id),
TyDecl::EnumVariantDecl(decl) => decl_engine.get_parsed_decl(decl.enum_ref.id()),
TyDecl::ImplSelfOrTrait(decl) => decl_engine.get_parsed_decl(&decl.decl_id),
TyDecl::AbiDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id),
TyDecl::GenericTypeForFunctionScope(_data) => None,
TyDecl::ErrorRecovery(_, _) => None,
TyDecl::StorageDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id),
TyDecl::TypeAliasDecl(decl) => decl_engine.get_parsed_decl(&decl.decl_id),
}
}

/// Retrieves the declaration as a `DeclId<TyEnumDecl>`.
///
/// Returns an error if `self` is not the [TyDecl][EnumDecl] variant.
Expand Down Expand Up @@ -535,7 +555,7 @@ impl TyDecl {
/// Retrieves the declaration as a `DeclRef<DeclId<TyStructDecl>>`.
///
/// Returns an error if `self` is not the [TyDecl][StructDecl] variant.
pub(crate) fn to_struct_id(
pub(crate) fn to_struct_decl(
&self,
handler: &Handler,
engines: &Engines,
Expand Down
Loading

0 comments on commit 159f049

Please sign in to comment.