use std::{
fmt::{self, Debug},
hash::{Hash, Hasher},
};
use sway_error::error::CompileError;
use sway_types::{Ident, Span};
use crate::{
decl_engine::*,
engine_threading::*,
error::*,
language::{parsed::TreeType, ty::*, Visibility},
transform::AttributeKind,
type_system::*,
types::DeterministicallyAborts,
};
pub trait GetDeclIdent {
fn get_decl_ident(&self) -> Option<Ident>;
}
pub trait GetDeclRef {
fn get_decl_ref(&self) -> Option<DeclRef>;
}
#[derive(Clone, Debug)]
pub struct TyAstNode {
pub content: TyAstNodeContent,
pub(crate) span: Span,
}
impl EqWithEngines for TyAstNode {}
impl PartialEqWithEngines for TyAstNode {
fn eq(&self, other: &Self, engines: Engines<'_>) -> bool {
self.content.eq(&other.content, engines)
}
}
impl HashWithEngines for TyAstNode {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
let TyAstNode {
content,
span: _,
} = self;
content.hash(state, engines);
}
}
impl DisplayWithEngines for TyAstNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: Engines<'_>) -> fmt::Result {
use TyAstNodeContent::*;
match &self.content {
Declaration(typed_decl) => DisplayWithEngines::fmt(typed_decl, f, engines),
Expression(exp) => DisplayWithEngines::fmt(exp, f, engines),
ImplicitReturnExpression(exp) => write!(f, "return {}", engines.help_out(exp)),
SideEffect(_) => f.write_str(""),
}
}
}
impl SubstTypes for TyAstNode {
fn subst_inner(&mut self, type_mapping: &TypeSubstMap, engines: Engines<'_>) {
match self.content {
TyAstNodeContent::ImplicitReturnExpression(ref mut exp) => {
exp.subst(type_mapping, engines)
}
TyAstNodeContent::Declaration(ref mut decl) => decl.subst(type_mapping, engines),
TyAstNodeContent::Expression(ref mut expr) => expr.subst(type_mapping, engines),
TyAstNodeContent::SideEffect(_) => (),
}
}
}
impl ReplaceSelfType for TyAstNode {
fn replace_self_type(&mut self, engines: Engines<'_>, self_type: TypeId) {
match self.content {
TyAstNodeContent::ImplicitReturnExpression(ref mut exp) => {
exp.replace_self_type(engines, self_type)
}
TyAstNodeContent::Declaration(ref mut decl) => {
decl.replace_self_type(engines, self_type)
}
TyAstNodeContent::Expression(ref mut expr) => {
expr.replace_self_type(engines, self_type)
}
TyAstNodeContent::SideEffect(_) => (),
}
}
}
impl ReplaceDecls for TyAstNode {
fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, engines: Engines<'_>) {
match self.content {
TyAstNodeContent::ImplicitReturnExpression(ref mut exp) => {
exp.replace_decls(decl_mapping, engines)
}
TyAstNodeContent::Declaration(_) => {}
TyAstNodeContent::Expression(ref mut expr) => expr.replace_decls(decl_mapping, engines),
TyAstNodeContent::SideEffect(_) => (),
}
}
}
impl CollectTypesMetadata for TyAstNode {
fn collect_types_metadata(
&self,
ctx: &mut CollectTypesMetadataContext,
) -> CompileResult<Vec<TypeMetadata>> {
self.content.collect_types_metadata(ctx)
}
}
impl DeterministicallyAborts for TyAstNode {
fn deterministically_aborts(&self, decl_engine: &DeclEngine, check_call_body: bool) -> bool {
use TyAstNodeContent::*;
match &self.content {
Declaration(_) => false,
Expression(exp) | ImplicitReturnExpression(exp) => {
exp.deterministically_aborts(decl_engine, check_call_body)
}
SideEffect(_) => false,
}
}
}
impl GetDeclIdent for TyAstNode {
fn get_decl_ident(&self) -> Option<Ident> {
self.content.get_decl_ident()
}
}
impl TyAstNode {
pub(crate) fn gather_return_statements(&self) -> Vec<&TyExpression> {
match &self.content {
TyAstNodeContent::ImplicitReturnExpression(ref exp) => exp.gather_return_statements(),
TyAstNodeContent::Declaration(TyDeclaration::VariableDeclaration(decl)) => {
decl.body.gather_return_statements()
}
TyAstNodeContent::Expression(exp) => exp.gather_return_statements(),
TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Declaration(_) => vec![],
}
}
pub(crate) fn is_public(&self, decl_engine: &DeclEngine) -> CompileResult<bool> {
let mut warnings = vec![];
let mut errors = vec![];
let public = match &self.content {
TyAstNodeContent::Declaration(decl) => {
let visibility = check!(
decl.visibility(decl_engine),
return err(warnings, errors),
warnings,
errors
);
visibility.is_public()
}
TyAstNodeContent::Expression(_)
| TyAstNodeContent::SideEffect(_)
| TyAstNodeContent::ImplicitReturnExpression(_) => false,
};
ok(public, warnings, errors)
}
pub(crate) fn is_generic_function(&self, decl_engine: &DeclEngine) -> CompileResult<bool> {
let mut warnings = vec![];
let mut errors = vec![];
match &self {
TyAstNode {
span,
content:
TyAstNodeContent::Declaration(TyDeclaration::FunctionDeclaration {
decl_id, ..
}),
..
} => {
let TyFunctionDeclaration {
type_parameters, ..
} = check!(
CompileResult::from(decl_engine.get_function(decl_id, span)),
return err(warnings, errors),
warnings,
errors
);
ok(!type_parameters.is_empty(), warnings, errors)
}
_ => ok(false, warnings, errors),
}
}
pub(crate) fn is_test_function(&self, decl_engine: &DeclEngine) -> CompileResult<bool> {
let mut warnings = vec![];
let mut errors = vec![];
match &self {
TyAstNode {
span,
content:
TyAstNodeContent::Declaration(TyDeclaration::FunctionDeclaration {
decl_id, ..
}),
..
} => {
let TyFunctionDeclaration { attributes, .. } = check!(
CompileResult::from(decl_engine.get_function(decl_id, span)),
return err(warnings, errors),
warnings,
errors
);
ok(
attributes.contains_key(&AttributeKind::Test),
warnings,
errors,
)
}
_ => ok(false, warnings, errors),
}
}
pub(crate) fn is_entry_point(
&self,
decl_engine: &DeclEngine,
tree_type: &TreeType,
) -> Result<bool, CompileError> {
match tree_type {
TreeType::Predicate | TreeType::Script => {
match self {
TyAstNode {
span,
content:
TyAstNodeContent::Declaration(TyDeclaration::FunctionDeclaration {
decl_id,
..
}),
..
} => {
let decl = decl_engine.get_function(decl_id, span)?;
Ok(decl.is_entry())
}
_ => Ok(false),
}
}
TreeType::Contract | TreeType::Library { .. } => match self {
TyAstNode {
content:
TyAstNodeContent::Declaration(TyDeclaration::FunctionDeclaration {
decl_id,
decl_span,
..
}),
..
} => {
let decl = decl_engine.get_function(decl_id, decl_span)?;
Ok(decl.visibility == Visibility::Public || decl.is_test())
}
TyAstNode {
content:
TyAstNodeContent::Declaration(TyDeclaration::TraitDeclaration {
decl_id,
decl_span,
..
}),
..
} => Ok(decl_engine
.get_trait(decl_id, decl_span)?
.visibility
.is_public()),
TyAstNode {
content:
TyAstNodeContent::Declaration(TyDeclaration::StructDeclaration {
decl_id,
decl_span,
..
}),
..
} => {
let struct_decl = decl_engine.get_struct(decl_id, decl_span)?;
Ok(struct_decl.visibility == Visibility::Public)
}
TyAstNode {
content: TyAstNodeContent::Declaration(TyDeclaration::ImplTrait { .. }),
..
} => Ok(true),
TyAstNode {
content:
TyAstNodeContent::Declaration(TyDeclaration::ConstantDeclaration {
decl_id,
decl_span,
..
}),
..
} => {
let decl = decl_engine.get_constant(decl_id, decl_span)?;
Ok(decl.visibility.is_public())
}
_ => Ok(false),
},
}
}
pub(crate) fn type_info(&self, type_engine: &TypeEngine) -> TypeInfo {
match &self.content {
TyAstNodeContent::Declaration(_) => TypeInfo::Tuple(Vec::new()),
TyAstNodeContent::Expression(TyExpression { return_type, .. }) => {
type_engine.get(*return_type)
}
TyAstNodeContent::ImplicitReturnExpression(TyExpression { return_type, .. }) => {
type_engine.get(*return_type)
}
TyAstNodeContent::SideEffect(_) => TypeInfo::Tuple(Vec::new()),
}
}
}
#[derive(Clone, Debug)]
pub enum TyAstNodeContent {
Declaration(TyDeclaration),
Expression(TyExpression),
ImplicitReturnExpression(TyExpression),
SideEffect(TySideEffect),
}
impl EqWithEngines for TyAstNodeContent {}
impl PartialEqWithEngines for TyAstNodeContent {
fn eq(&self, other: &Self, engines: Engines<'_>) -> bool {
match (self, other) {
(Self::Declaration(x), Self::Declaration(y)) => x.eq(y, engines),
(Self::Expression(x), Self::Expression(y)) => x.eq(y, engines),
(Self::ImplicitReturnExpression(x), Self::ImplicitReturnExpression(y)) => {
x.eq(y, engines)
}
(Self::SideEffect(_), Self::SideEffect(_)) => true,
_ => false,
}
}
}
impl HashWithEngines for TyAstNodeContent {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
use TyAstNodeContent::*;
std::mem::discriminant(self).hash(state);
match self {
Declaration(decl) => {
decl.hash(state, engines);
}
Expression(exp) | ImplicitReturnExpression(exp) => {
exp.hash(state, engines);
}
SideEffect(effect) => {
effect.hash(state);
}
}
}
}
impl CollectTypesMetadata for TyAstNodeContent {
fn collect_types_metadata(
&self,
ctx: &mut CollectTypesMetadataContext,
) -> CompileResult<Vec<TypeMetadata>> {
use TyAstNodeContent::*;
match self {
Declaration(decl) => decl.collect_types_metadata(ctx),
Expression(expr) => expr.collect_types_metadata(ctx),
ImplicitReturnExpression(expr) => expr.collect_types_metadata(ctx),
SideEffect(_) => ok(vec![], vec![], vec![]),
}
}
}
impl GetDeclIdent for TyAstNodeContent {
fn get_decl_ident(&self) -> Option<Ident> {
match self {
TyAstNodeContent::Declaration(decl) => decl.get_decl_ident(),
TyAstNodeContent::Expression(_expr) => None, TyAstNodeContent::ImplicitReturnExpression(_expr) => None, TyAstNodeContent::SideEffect(_) => None,
}
}
}