Skip to content

Commit

Permalink
Merge branch 'main' into feat/ast-validations-p8
Browse files Browse the repository at this point in the history
  • Loading branch information
TilakMaddy authored Dec 13, 2024
2 parents 16be6a6 + 76fc3a2 commit 52f8c7b
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 36 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,28 @@ concurrency:
cancel-in-progress: true

jobs:
codspeed:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Install cargo-codspeed
uses: taiki-e/install-action@v2
with:
tool: cargo-codspeed
- name: Build the benchmark target(s)
run: cargo codspeed build --profile profiling -p solar-bench criterion
- name: Run the benchmarks
uses: CodSpeedHQ/action@v3
with:
run: cargo codspeed run -p solar-bench criterion
token: ${{ secrets.CODSPEED_TOKEN }}

iai:
runs-on: ubuntu-latest
env:
Expand Down
26 changes: 24 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions benches/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ slang_solidity = "=0.18.3"
semver.workspace = true

[dev-dependencies]
criterion = "0.5"
criterion = { package = "codspeed-criterion-compat", version = "2.7" }
iai-callgrind = "0.14"
paste.workspace = true

[features]
ci = []

[[bench]]
name = "bench"
path = "benches/bench.rs"
name = "criterion"
path = "benches/criterion.rs"
harness = false

[[bench]]
Expand Down
4 changes: 3 additions & 1 deletion benches/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Run with:

```bash
# Criterion
cargo criterion -p solar-bench --bench bench -- --quiet --format terse |& tee benches/tables.in
cargo criterion -p solar-bench --bench criterion -- --quiet --format terse |& tee benches/tables.in
./benches/tables.py ./benches/README.md < benches/tables.in

# iai - requires `valgrind` and `iai-callgrind-runner`
Expand All @@ -20,6 +20,8 @@ invoking other commands such as `cargo test`.

## Results

You view the Solar-only results on [codspeed.io](https://codspeed.io/paradigmxyz/solar).

The following results were achieved on:
- Target: `x86_64-unknown-linux-gnu`
- CPU: AMD Ryzen 9 7950X;
Expand Down
13 changes: 9 additions & 4 deletions benches/benches/bench.rs → benches/benches/criterion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,17 @@ fn parser_benches(c: &mut Criterion) {
for &Source { name: sname, path: _, src } in get_srcs() {
for &parser in PARSERS {
let pname = parser.name();
let mk_id = |id: &str| {
if PARSERS.len() == 1 {
format!("{sname}/{id}")
} else {
format!("{sname}/{pname}/{id}")
}
};
if parser.can_lex() {
let id = format!("{sname}/{pname}/lex");
g.bench_function(id, |b| b.iter(|| parser.lex(src)));
g.bench_function(mk_id("lex"), |b| b.iter(|| parser.lex(src)));
}
let id = format!("{sname}/{pname}/parse");
g.bench_function(id, |b| b.iter(|| parser.parse(src)));
g.bench_function(mk_id("parse"), |b| b.iter(|| parser.parse(src)));
}
eprintln!();
}
Expand Down
4 changes: 3 additions & 1 deletion benches/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use std::{
process::Stdio,
};

pub const PARSERS: &[&dyn Parser] = &[&Solc, &Solar, &Solang, &Slang];
#[allow(unexpected_cfgs)]
pub const PARSERS: &[&dyn Parser] =
if cfg!(codspeed) { &[&Solar] } else { &[&Solc, &Solar, &Solang, &Slang] };

pub fn get_srcs() -> &'static [Source] {
static CACHE: std::sync::OnceLock<Vec<Source>> = std::sync::OnceLock::new();
Expand Down
2 changes: 1 addition & 1 deletion crates/ast/src/ast/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ pub struct ItemFunction<'ast> {
}

impl ItemFunction<'_> {
/// Returns `true` if the function is implemented
/// Returns `true` if the function is implemented.
pub fn is_implemented(&self) -> bool {
self.body.is_some()
}
Expand Down
48 changes: 24 additions & 24 deletions crates/sema/src/ast_passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,24 @@ pub fn validate(sess: &Session, ast: &ast::SourceUnit<'_>) {

/// AST validator.
struct AstValidator<'sess, 'ast> {
span: Span,
item_span: Span,
dcx: &'sess DiagCtxt,
contract: Option<&'ast ast::ItemContract<'ast>>,
function_kind: Option<ast::FunctionKind>,
in_unchecked_block: bool,
in_loop_depth: u64,
placeholder_count: u64,
loop_depth: u32,
placeholder_count: u32,
}

impl<'sess> AstValidator<'sess, '_> {
fn new(sess: &'sess Session) -> Self {
Self {
span: Span::DUMMY,
item_span: Span::DUMMY,
dcx: &sess.dcx,
contract: None,
function_kind: None,
in_unchecked_block: false,
in_loop_depth: 0,
loop_depth: 0,
placeholder_count: 0,
}
}
Expand All @@ -48,7 +48,7 @@ impl<'sess> AstValidator<'sess, '_> {
}

fn in_loop(&self) -> bool {
self.in_loop_depth != 0
self.loop_depth != 0
}

fn check_single_statement_variable_declaration(&self, stmt: &ast::Stmt<'_>) {
Expand Down Expand Up @@ -98,7 +98,7 @@ impl<'ast> Visit<'ast> for AstValidator<'_, 'ast> {
type BreakValue = Never;

fn visit_item(&mut self, item: &'ast ast::Item<'ast>) -> ControlFlow<Self::BreakValue> {
self.span = item.span;
self.item_span = item.span;
self.walk_item(item)
}

Expand Down Expand Up @@ -147,15 +147,15 @@ impl<'ast> Visit<'ast> for AstValidator<'_, 'ast> {
("experimental", Some("SMTChecker")) => {}
("experimental", Some("solidity")) => {
let msg = "experimental solidity features are not supported";
self.dcx().err(msg).span(self.span).emit();
self.dcx().err(msg).span(self.item_span).emit();
}
_ => {
self.dcx().err("unknown pragma").span(self.span).emit();
self.dcx().err("unknown pragma").span(self.item_span).emit();
}
}
}
ast::PragmaTokens::Verbatim(_) => {
self.dcx().err("unknown pragma").span(self.span).emit();
self.dcx().err("unknown pragma").span(self.item_span).emit();
}
}
ControlFlow::Continue(())
Expand All @@ -166,10 +166,10 @@ impl<'ast> Visit<'ast> for AstValidator<'_, 'ast> {
ast::StmtKind::While(_, body)
| ast::StmtKind::DoWhile(body, _)
| ast::StmtKind::For { body, .. } => {
self.in_loop_depth += 1;
self.loop_depth += 1;
self.check_single_statement_variable_declaration(body);
let r = self.walk_stmt(stmt);
self.in_loop_depth -= 1;
self.loop_depth -= 1;
return r;
}
ast::StmtKind::If(_cond, then, else_) => {
Expand Down Expand Up @@ -263,12 +263,12 @@ impl<'ast> Visit<'ast> for AstValidator<'_, 'ast> {
if contract.kind.is_interface() && !func.header.modifiers.is_empty() {
self.dcx()
.err("functions in interfaces cannot have modifiers")
.span(self.span)
.span(self.item_span)
.emit();
} else if !func.is_implemented() && !func.header.modifiers.is_empty() {
self.dcx()
.err("functions without implementation cannot have modifiers")
.span(self.span)
.span(self.item_span)
.emit();
}
}
Expand All @@ -277,22 +277,22 @@ impl<'ast> Visit<'ast> for AstValidator<'_, 'ast> {
if self.contract.is_some_and(|c| c.kind.is_library()) {
self.dcx()
.err("libraries cannot have receive ether functions")
.span(self.span)
.span(self.item_span)
.emit();
}

if !func.header.state_mutability.is_payable() {
self.dcx()
.err("receive ether function must be payable")
.span(self.span)
.span(self.item_span)
.help("add `payable` state mutability")
.emit();
}

if !func.header.parameters.is_empty() {
self.dcx()
.err("receive ether function cannot take parameters")
.span(self.span)
.span(self.item_span)
.emit();
}
}
Expand All @@ -308,7 +308,7 @@ impl<'ast> Visit<'ast> for AstValidator<'_, 'ast> {
} {
self.dcx()
.err("no visibility specified")
.span(self.span)
.span(self.item_span)
.help(format!("add `{suggested_visibility}` to the declaration"))
.emit();
}
Expand All @@ -317,12 +317,12 @@ impl<'ast> Visit<'ast> for AstValidator<'_, 'ast> {

if self.contract.is_none() && func.kind.is_function() {
if !func.is_implemented() {
self.dcx().err("free functions must be implemented").span(self.span).emit();
self.dcx().err("free functions must be implemented").span(self.item_span).emit();
}
if let Some(visibility) = func.header.visibility {
self.dcx()
.err("free functions cannot have visibility")
.span(self.span)
.span(self.item_span)
.help(format!("remove `{visibility}` from the declaration"))
.emit();
}
Expand Down Expand Up @@ -355,23 +355,23 @@ impl<'ast> Visit<'ast> for AstValidator<'_, 'ast> {
if self.contract.is_none() && !with_typ {
self.dcx()
.err("the type has to be specified explicitly at file level (cannot use `*`)")
.span(self.span)
.span(self.item_span)
.emit();
}
if *global && !with_typ {
self.dcx()
.err("can only globally attach functions to specific types")
.span(self.span)
.span(self.item_span)
.emit();
}
if *global && self.contract.is_some() {
self.dcx().err("`global` can only be used at file level").span(self.span).emit();
self.dcx().err("`global` can only be used at file level").span(self.item_span).emit();
}
if let Some(contract) = self.contract {
if contract.kind.is_interface() {
self.dcx()
.err("the `using for` directive is not allowed inside interfaces")
.span(self.span)
.span(self.item_span)
.emit();
}
}
Expand Down

0 comments on commit 52f8c7b

Please sign in to comment.