Skip to content

Commit

Permalink
Merge branch 'master' into xunilrj/asm-block-uninitialized-reg
Browse files Browse the repository at this point in the history
  • Loading branch information
IGI-111 authored Oct 27, 2023
2 parents 8529d3d + de13543 commit 12e5a60
Show file tree
Hide file tree
Showing 47 changed files with 2,802 additions and 704 deletions.
73 changes: 73 additions & 0 deletions sway-core/src/compiler_generated.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//! This module encapsulates generation of various elements generated internally by the compiler,
//! e.g., unique names of variables in desugared code and similar.
//! It also provides functions for inspecting such generated elements.
use std::usize;

/// The prefix for the compiler generated names of tuples.
const TUPLE_VAR_NAME_PREFIX: &str = "__tuple_";

pub(crate) fn generate_tuple_var_name(suffix: usize) -> String {
format!("{TUPLE_VAR_NAME_PREFIX}{suffix}")
}

pub fn is_generated_tuple_var_name(name: &str) -> bool {
name.starts_with(TUPLE_VAR_NAME_PREFIX)
}

/// The prefix for the compiler generated names of structs used in destructuring
/// structs in `let` statements.
const DESTRUCTURED_STRUCT_VAR_NAME_PREFIX: &str = "__destructured_struct_";

pub(crate) fn generate_destructured_struct_var_name(suffix: usize) -> String {
format!("{DESTRUCTURED_STRUCT_VAR_NAME_PREFIX}{suffix}")
}

pub fn is_generated_destructured_struct_var_name(name: &str) -> bool {
name.starts_with(DESTRUCTURED_STRUCT_VAR_NAME_PREFIX)
}

/// The prefix for the compiler generated names of
/// variables that store values matched in match expressions.
const MATCHED_VALUE_VAR_NAME_PREFIX: &str = "__matched_value_";

pub(crate) fn generate_matched_value_var_name(suffix: usize) -> String {
format!("{MATCHED_VALUE_VAR_NAME_PREFIX}{suffix}")
}

/// The prefix for the compiler generated names of
/// variables that store 1-based index of the OR match
/// alternative that gets matched, or zero if non of the
/// OR alternatives get matched.
const MATCHED_OR_VARIANT_INDEX_VAR_NAME_PREFIX: &str = "__matched_or_variant_index_";

pub(crate) fn generate_matched_or_variant_index_var_name(suffix: usize) -> String {
format!("{MATCHED_OR_VARIANT_INDEX_VAR_NAME_PREFIX}{suffix}")
}

/// The prefix for the compiler generated names of
/// tuple variables that store values of the variables declared
/// in OR match alternatives.
const MATCHED_OR_VARIANT_VARIABLES_VAR_NAME_PREFIX: &str = "__matched_or_variant_variables_";

pub(crate) fn generate_matched_or_variant_variables_var_name(suffix: usize) -> String {
format!("{MATCHED_OR_VARIANT_VARIABLES_VAR_NAME_PREFIX}{suffix}")
}

pub fn is_generated_any_match_expression_var_name(name: &str) -> bool {
name.starts_with(MATCHED_VALUE_VAR_NAME_PREFIX)
|| name.starts_with(MATCHED_OR_VARIANT_INDEX_VAR_NAME_PREFIX)
|| name.starts_with(MATCHED_OR_VARIANT_VARIABLES_VAR_NAME_PREFIX)
}

/// A revert with this value signals that it was caused by an internal compiler error that
/// occurred during the flattening of match arms that contain variables in OR match patterns.
///
/// The value is: 14757395258967588865
pub(crate) const INVALID_MATCHED_OR_VARIABLE_INDEX_SIGNAL: u64 = 0xcccc_cccc_cccc_0001;

/// A revert with this value signals that it was caused by an internal compiler error that
/// occurred during the flattening of match arms that contain variables in OR match patterns.
///
/// The value is: 14757395258967588866
pub(crate) const INVALID_DESUGARED_MATCHED_EXPRESSION_SIGNAL: u64 = 0xcccc_cccc_cccc_0002;
4 changes: 2 additions & 2 deletions sway-core/src/language/call_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ impl DebugWithEngines for QualifiedCallPath {
}
}

/// in the expression `a::b::c()`, `a` and `b` are the prefixes and `c` is the suffix.
/// In the expression `a::b::c()`, `a` and `b` are the prefixes and `c` is the suffix.
/// `c` can be any type `T`, but in practice `c` is either an `Ident` or a `TypeInfo`.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct CallPath<T = Ident> {
Expand Down Expand Up @@ -279,7 +279,7 @@ impl CallPath {
.collect::<Vec<_>>()
}

/// Convert a given [CallPath] to an symbol to a full [CallPath] from the root of the project
/// Convert a given [CallPath] to a symbol to a full [CallPath] from the root of the project
/// in which the symbol is declared. For example, given a path `pkga::SOME_CONST` where `pkga`
/// is an _internal_ library of a package named `my_project`, the corresponding call path is
/// `my_project::pkga::SOME_CONST`.
Expand Down
1 change: 1 addition & 0 deletions sway-core/src/language/ty/declaration/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ impl TyFunctionDecl {
pub(crate) fn parameters_span(&self) -> Span {
if !self.parameters.is_empty() {
self.parameters.iter().fold(
// TODO: Use Span::join_all().
self.parameters[0].name.span(),
|acc, TyFunctionParameter { type_argument, .. }| {
Span::join(acc, type_argument.span.clone())
Expand Down
28 changes: 25 additions & 3 deletions sway-core/src/language/ty/expression/match_expression.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
use sway_types::Span;
use sway_types::{Ident, Span};

use crate::{language::ty::*, semantic_analysis::MatchReqMap, type_system::*};
use crate::{language::ty::*, type_system::*};

/// [TyExpression] of type bool that contains the condition to be used
/// in the desugared if expression or `None` if the match arm is
/// a catch-all arm without condition.
/// E.g., a condition might look like:
/// `__matched_value_1.x == 11 && __matched_value_1.y == 22 || __matched_value_1.x == 33 && __matched_value_1.y == 44`
pub(crate) type MatchBranchCondition = Option<TyExpression>;

/// [TyExpression]s of the form `let <ident> = <expression>` where
/// `<ident>` is a name of a generated variable that holds the
/// index of the matched OR variant.
/// `<expression>` is an `if-else` expression that returns
/// the 1-based index of the matched OR variant or zero
/// if non of the variants match.
pub(crate) type MatchedOrVariantIndexVars = Vec<(Ident, TyExpression)>;

#[derive(Debug)]
pub(crate) struct TyMatchExpression {
Expand All @@ -12,7 +27,14 @@ pub(crate) struct TyMatchExpression {

#[derive(Debug)]
pub(crate) struct TyMatchBranch {
pub(crate) cnf: MatchReqMap,
/// Declarations of the variables that hold the 1-based index
/// of a matched OR variant or zero if non of the variants match.
pub(crate) matched_or_variant_index_vars: MatchedOrVariantIndexVars,
/// A boolean expression that represents the total match arm requirement,
/// or `None` if the match arm is a catch-all arm.
pub(crate) condition: MatchBranchCondition,
/// The resulting [crate::ty::TyCodeBlock] that includes the match arm variable declarations
/// and the typed result from the original untyped branch result.
pub(crate) result: TyExpression,
#[allow(dead_code)]
pub(crate) span: Span,
Expand Down
1 change: 1 addition & 0 deletions sway-core/src/language/ty/expression/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl HashWithEngines for TyStorageAccess {

impl Spanned for TyStorageAccess {
fn span(&self) -> Span {
// TODO: Use Span::join_all().
self.fields
.iter()
.fold(self.fields[0].span.clone(), |acc, field| {
Expand Down
1 change: 1 addition & 0 deletions sway-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod abi_generation;
pub mod asm_generation;
mod asm_lang;
mod build_config;
pub mod compiler_generated;
mod concurrent_slab;
mod control_flow_analysis;
pub mod decl_engine;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@ mod analysis;
mod typed;

pub(crate) use analysis::*;
pub(crate) use typed::*;
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
use sway_error::handler::{ErrorEmitted, Handler};
use sway_types::{integer_bits::IntegerBits, Ident, Span};

use crate::{
language::{ty, LazyOp, Literal},
semantic_analysis::{
typed_expression::{instantiate_lazy_operator, instantiate_tuple_index_access},
TypeCheckContext,
},
Engines, TypeId, TypeInfo,
};

/// Simplifies instantiation of desugared code in the match expression and match arms.
pub(super) struct Instantiate {
/// Both dummy span for instantiation of desugared elements
/// and error span for internal compiler errors.
span: Span,
u64_type: TypeId,
boolean_type: TypeId,
revert_type: TypeId,
}

impl Instantiate {
pub(super) fn new(engines: &Engines, span: Span) -> Self {
let type_engine = engines.te();
let u64_type =
type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour));
let boolean_type = type_engine.insert(engines, TypeInfo::Boolean);
let revert_type = type_engine.insert(engines, TypeInfo::Unknown); // TODO: Change this to the `Never` type once available.

Self {
span,
u64_type,
boolean_type,
revert_type,
}
}

pub(super) fn dummy_span(&self) -> Span {
self.span.clone()
}

pub(super) fn error_span(&self) -> Span {
self.span.clone()
}

pub(super) fn u64_type(&self) -> TypeId {
self.u64_type
}

/// Instantiates a [ty::TyDecl::VariableDecl] for an immutable variable of the form `let <name> = <body>;`.
pub(super) fn var_decl(&self, name: Ident, body: ty::TyExpression) -> ty::TyDecl {
let return_type = body.return_type;
let type_ascription = body.return_type.into();

ty::TyDecl::VariableDecl(Box::new(ty::TyVariableDecl {
name,
body,
mutability: ty::VariableMutability::Immutable,
return_type,
type_ascription,
}))
}

/// Instantiates a [ty::TyExpressionVariant::VariableExpression] for accessing an immutable variable
/// `name` of the type `type_id`.
pub(super) fn var_exp(&self, name: Ident, type_id: TypeId) -> ty::TyExpression {
ty::TyExpression {
expression: ty::TyExpressionVariant::VariableExpression {
name,
span: self.dummy_span(),
mutability: ty::VariableMutability::Immutable,
call_path: None,
},
return_type: type_id,
span: self.dummy_span(),
}
}

/// Instantiates a [ty::TyExpressionVariant::Literal] that represents a `u64` `value`.
pub(super) fn u64_literal(&self, value: u64) -> ty::TyExpression {
ty::TyExpression {
expression: ty::TyExpressionVariant::Literal(Literal::U64(value)),
return_type: self.u64_type,
span: self.dummy_span(),
}
}

/// Instantiates a [ty::TyExpressionVariant::Literal] that represents a `boolean` `value`.
pub(super) fn boolean_literal(&self, value: bool) -> ty::TyExpression {
ty::TyExpression {
expression: ty::TyExpressionVariant::Literal(Literal::Boolean(value)),
return_type: self.boolean_type,
span: self.dummy_span(),
}
}

/// Instantiates an [Ident] with overridden `name`.
pub(super) fn ident(&self, name: String) -> Ident {
Ident::new_with_override(name, self.dummy_span())
}

/// Instantiates a [ty::TyExpressionVariant::CodeBlock] with a single
/// [ty::TyAstNodeContent::ImplicitReturnExpression] that returns the `value`.
pub(super) fn code_block_with_implicit_return_u64(&self, value: u64) -> ty::TyExpression {
ty::TyExpression {
expression: ty::TyExpressionVariant::CodeBlock(ty::TyCodeBlock {
contents: vec![ty::TyAstNode {
content: ty::TyAstNodeContent::ImplicitReturnExpression(ty::TyExpression {
expression: ty::TyExpressionVariant::Literal(Literal::U64(value)),
return_type: self.u64_type,
span: self.dummy_span(),
}),
span: self.dummy_span(),
}],
}),
return_type: self.u64_type,
span: self.dummy_span(),
}
}

/// Instantiates a [ty::TyExpressionVariant::CodeBlock] with a single
/// [ty::TyAstNodeContent::ImplicitReturnExpression] that returns calls `__revert(revert_code)`.
pub(super) fn code_block_with_implicit_return_revert(
&self,
revert_code: u64,
) -> ty::TyExpression {
ty::TyExpression {
expression: ty::TyExpressionVariant::CodeBlock(ty::TyCodeBlock {
contents: vec![ty::TyAstNode {
content: ty::TyAstNodeContent::ImplicitReturnExpression(ty::TyExpression {
expression: ty::TyExpressionVariant::IntrinsicFunction(
ty::TyIntrinsicFunctionKind {
kind: sway_ast::Intrinsic::Revert,
arguments: vec![ty::TyExpression {
expression: ty::TyExpressionVariant::Literal(Literal::U64(
revert_code,
)),
return_type: self.u64_type,
span: self.dummy_span(),
}],
type_arguments: vec![],
span: self.dummy_span(),
},
),
return_type: self.revert_type,
span: self.dummy_span(),
}),
span: self.dummy_span(),
}],
}),
return_type: self.revert_type,
span: self.dummy_span(),
}
}

/// Instantiates an expression equivalent to `<lhs> == <rhs>`.
pub(super) fn eq_result(
&self,
handler: &Handler,
ctx: TypeCheckContext,
lhs: ty::TyExpression,
rhs: ty::TyExpression,
) -> Result<ty::TyExpression, ErrorEmitted> {
ty::TyExpression::core_ops_eq(handler, ctx, vec![lhs, rhs], self.dummy_span())
}

/// Instantiates an expression equivalent to `<lhs> != <rhs>`.
pub(super) fn neq_result(
&self,
handler: &Handler,
ctx: TypeCheckContext,
lhs: ty::TyExpression,
rhs: ty::TyExpression,
) -> Result<ty::TyExpression, ErrorEmitted> {
ty::TyExpression::core_ops_neq(handler, ctx, vec![lhs, rhs], self.dummy_span())
}

/// Instantiates an expression equivalent to `<lhs> == <rhs>`. The method expects that
/// the expression can be instantiated and panics if that's not the case.
pub(super) fn eq(
&self,
ctx: TypeCheckContext,
lhs: ty::TyExpression,
rhs: ty::TyExpression,
) -> ty::TyExpression {
ty::TyExpression::core_ops_eq(&Handler::default(), ctx, vec![lhs, rhs], self.dummy_span())
.expect("Instantiating `core::ops::eq` is expected to always work.")
}

/// Instantiates a [ty::TyExpressionVariant::TupleElemAccess] `<tuple_variable>.<index>`. The method expects that
/// the expression can be instantiated and panics if that's not the case.
pub(super) fn tuple_elem_access(
&self,
engines: &Engines,
tuple_variable: ty::TyExpression,
index: usize,
) -> ty::TyExpression {
instantiate_tuple_index_access(
&Handler::default(),
engines,
tuple_variable,
index,
self.dummy_span(),
self.dummy_span(),
)
.expect("Instantiating tuple element access expression is expected to always work.")
}

/// Instantiates a [LazyOp::And] expression of the form `<lhs> && <rhs>`.
pub(super) fn lazy_and(
&self,
lhs: ty::TyExpression,
rhs: ty::TyExpression,
) -> ty::TyExpression {
instantiate_lazy_operator(LazyOp::And, lhs, rhs, self.boolean_type, self.dummy_span())
}

/// Instantiates a [LazyOp::Or] expression of the form `<lhs> || <rhs>`.
pub(super) fn lazy_or(&self, lhs: ty::TyExpression, rhs: ty::TyExpression) -> ty::TyExpression {
instantiate_lazy_operator(LazyOp::Or, lhs, rhs, self.boolean_type, self.dummy_span())
}
}
Loading

0 comments on commit 12e5a60

Please sign in to comment.