Skip to content

Commit

Permalink
Fix skipped function typecheck (#311)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer committed Sep 5, 2023
1 parent 4354847 commit ea32753
Show file tree
Hide file tree
Showing 47 changed files with 717 additions and 428 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ jobs:
uses: actions/cache@v3
with:
path: /home/runner/work/spice/llvm
key: llvm-17.0.0-rc3
key: llvm-17.0.0-rc4

- name: Setup LLVM
if: steps.cache-llvm.outputs.cache-hit != 'true'
run: |
cd ..
rm -rf llvm
git clone --depth 1 --branch llvmorg-17.0.0-rc3 https://github.com/llvm/llvm-project llvm
git clone --depth 1 --branch llvmorg-17.0.0-rc4 https://github.com/llvm/llvm-project llvm
mkdir ./llvm/build
cd ./llvm/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -DLLVM_ENABLE_RTTI=ON -GNinja ../llvm
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ jobs:
uses: actions/cache@v3
with:
path: /home/runner/work/spice/llvm
key: llvm-17.0.0-rc3
key: llvm-17.0.0-rc4

- name: Setup LLVM
if: steps.cache-llvm.outputs.cache-hit != 'true'
run: |
echo "/usr/lib/ccache:/usr/local/opt/ccache/libexec" >> $GITHUB_PATH
cd ..
git clone --depth 1 --branch llvmorg-17.0.0-rc3 https://github.com/llvm/llvm-project llvm
git clone --depth 1 --branch llvmorg-17.0.0-rc4 https://github.com/llvm/llvm-project llvm
mkdir ./llvm/build
cd ./llvm/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -DLLVM_ENABLE_RTTI=ON -GNinja ../llvm
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ jobs:
uses: actions/cache@v3
with:
path: /home/runner/work/spice/spice/llvm
key: llvm-17.0.0-rc3-linux-x64
key: llvm-17.0.0-rc4-linux-x64

- name: Setup LLVM
if: steps.cache-llvm.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --branch llvmorg-17.0.0-rc3 https://github.com/llvm/llvm-project.git llvm
git clone --depth 1 --branch llvmorg-17.0.0-rc4 https://github.com/llvm/llvm-project.git llvm
mkdir ./llvm/build
cd ./llvm/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -DLLVM_ENABLE_RTTI=ON -GNinja -Wno-dev -Wattributes ../llvm
Expand Down Expand Up @@ -116,12 +116,12 @@ jobs:
uses: actions/cache@v3
with:
path: D:/a/spice/spice/llvm
key: llvm-17.0.0-rc3-win-x64
key: llvm-17.0.0-rc4-win-x64

- name: Setup LLVM
if: steps.cache-llvm.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --branch llvmorg-17.0.0-rc3 https://github.com/llvm/llvm-project.git llvm
git clone --depth 1 --branch llvmorg-17.0.0-rc4 https://github.com/llvm/llvm-project.git llvm
setx /M PATH "%PATH%;C:\mingw64\mingw64\bin"
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
echo "Adding MinGW to path done."
Expand Down
2 changes: 1 addition & 1 deletion .run/spice.run.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="build -d -O0 -g -ir ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="build -d -O0 -ir ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<envs>
<env name="SPICE_STD_DIR" value="$PROJECT_DIR$/std" />
</envs>
Expand Down
2 changes: 1 addition & 1 deletion dev-setup.bat
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ echo done.

REM - Clone LLVM
echo [Step 2] Cloning LLVM (Could take a while) ...
git clone --depth 1 --branch llvmorg-17.0.0-rc3 https://github.com/llvm/llvm-project llvm
git clone --depth 1 --branch llvmorg-17.0.0-rc4 https://github.com/llvm/llvm-project llvm
echo done.

REM - Build LLVM
Expand Down
2 changes: 1 addition & 1 deletion dev-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ colored_echo "done."

# Clone LLVM
colored_echo "[Step 2] Cloning LLVM (Could take a while) ... "
git clone --depth 1 --branch llvmorg-17.0.0-rc3 https://github.com/llvm/llvm-project llvm
git clone --depth 1 --branch llvmorg-17.0.0-rc4 https://github.com/llvm/llvm-project llvm
colored_echo "done."

# Build LLVM
Expand Down
43 changes: 41 additions & 2 deletions docs/docs/how-to/cli-parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,45 @@ $ ./app-name --hi
Hi!
```

## Add sub-commands
## Add subcommands

ToDo
To build more advanced CLI interfaces, you can add subcommands. Let's add a `greet` subcommand to our CLI interface:

```spice
// app-name.spice
import "std/io/cli-parser";
f<int> main(int argc, string[] argv) {
CliParser cli = CliParser("app-name", "Short description of the app");
cli.setVersion("v1.0.0");
cli.setFooter("(c) 2023 by John Doe");
CliSubcommand& greet = cli.addSubcommand("greet", "Greet someone");
CliSubcommand& walk = cli.addSubcommand("walk", "Walk somewhere");
cli.parse(argc, argv);
}
```

Each subcommand comes with its own `--help` flag out of the box, that prints the help text for that specific subcommand.
Subcommands can also have their own sub-commands. In other words, they can be nested:

```spice
// app-name.spice
import "std/io/cli-parser";
f<int> main(int argc, string[] argv) {
CliParser cli = CliParser("app-name", "Short description of the app");
cli.setVersion("v1.0.0");
cli.setFooter("(c) 2023 by John Doe");
CliSubcommand& greet = cli.addSubcommand("greet", "Greet someone");
CliSubcommand& greetFriendly = greet.addSubcommand("friendly", "Greet someone in a friendly way");
CliSubcommand& greetFormal = greet.addSubcommand("formal", "Greet someone in a formal way");
CliSubcommand& walk = cli.addSubcommand("walk", "Walk somewhere");
cli.parse(argc, argv);
}
```
4 changes: 2 additions & 2 deletions docs/docs/how-to/web-assembly.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Leveraging Spice WebAssembly capabilities
title: Compile to WebAssembly
---

Due to the fact, that Spice uses LLVM as compiler backbone, it is capable of cross-compiling to many different target
Expand Down Expand Up @@ -77,7 +77,7 @@ WebAssembly.instantiateStreaming(fetch('main.wasm'))
const stopWasm = window.performance.now();
console.log("Fibonacci Spice wasm: " + result);
console.log("Duration (millis): " + (stopWasm - startWasm));
// JS
// JavaScript
const startJS = window.performance.now();
result = fibo(fiboBase);
const stopJS = window.performance.now();
Expand Down
64 changes: 62 additions & 2 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -1,21 +1,81 @@
import "std/os/thread-pool";
import "std/io/cli-parser";

type CliOptions struct {
bool sayHi = false
}

p callback(bool& value) {
printf("Callback called with value %d\n", value);
}

f<int> main(int argc, string[] argv) {
CliParser parser = CliParser("Test Program", "This is a simple test program");
parser.setVersion("v0.1.0");
parser.setFooter("Copyright (c) Marc Auberer 2021-2023");

CliOptions options;
parser.addFlag("--hi", options.sayHi, "Say hi to the user");
parser.addFlag("--callback", callback, "Call a callback function");
parser.addFlag("-cb", p(bool& value) {
printf("CB called with value %d\n", value);
}, "Call a callback function");

parser.parse(argc, argv);

// Print hi if requested
if options.sayHi {
printf("Hi!\n");
}
}

/*import "std/os/thread-pool";
import "std/time/delay";

f<int> main() {
ThreadPool tp = ThreadPool(3s);
tp.enqueue(p() {
delay(100);
printf("Hello from task 1\n");
});
tp.enqueue(p() {
delay(200);
printf("Hello from task 2\n");
});
tp.enqueue(p() {
delay(300);
printf("Hello from task 3\n");
});
tp.enqueue(p() {
delay(400);
printf("Hello from task 4\n");
});
tp.enqueue(p() {
delay(500);
printf("Hello from task 5\n");
});
tp.enqueue(p() {
delay(600);
printf("Hello from task 6\n");
});
tp.enqueue(p() {
delay(700);
printf("Hello from task 7\n");
});
tp.enqueue(p() {
delay(800);
printf("Hello from task 8\n");
});
tp.enqueue(p() {
delay(900);
printf("Hello from task 9\n");
});
tp.enqueue(p() {
delay(1000);
printf("Hello from task 10\n");
});
tp.start();
}
tp.join();
}*/

/*import "std/os/thread-pool";

Expand Down
2 changes: 1 addition & 1 deletion src-bootstrap/SourceFile.spice
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public type SourceFile struct {

GlobalResourceManager& resourceManager
unsigned short importedRuntimeModules = 0
unsigned short typeCheckerRuns = 0
unsigned short totalTypeCheckerRuns = 0
}

public p SourceFile.ctor(GlobalResourceManager &resourceManager, SourceFile* parent, string name, string filePath, bool stdFile) {
Expand Down
9 changes: 5 additions & 4 deletions src/SourceFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,16 +267,18 @@ void SourceFile::runTypeCheckerPre() { // NOLINT(misc-no-recursion)

void SourceFile::runTypeCheckerPost() { // NOLINT(misc-no-recursion)
// Skip if restored from cache, this stage has already been done or not all dependants finished type checking
if (restoredFromCache || previousStage >= TYPE_CHECKER_POST || !haveAllDependantsBeenTypeChecked())
if (restoredFromCache || !haveAllDependantsBeenTypeChecked())
return;

Timer timer(&compilerOutput.times.typeCheckerPost);
timer.start();

// Start type-checking loop. The type-checker can request a re-execution. The max number of type-checker runs is limited
TypeChecker typeChecker(resourceManager, this, TC_MODE_CHECK);
unsigned short typeCheckerRuns = 0;
do {
typeCheckerRuns++;
totalTypeCheckerRuns++;

// Type-check the current file first. Multiple times, if requested
timer.resume();
Expand All @@ -288,7 +290,7 @@ void SourceFile::runTypeCheckerPost() { // NOLINT(misc-no-recursion)
sourceFile.first->runTypeCheckerPost();

// GCOV_EXCL_START
if (typeCheckerRuns >= 10)
if (typeCheckerRuns >= 10 || totalTypeCheckerRuns >= 50)
throw CompilerError(TYPE_CHECKER_RUNS_EXCEEDED, "Number of type checker runs for one source file exceeded. Please report "
"this as a bug on GitHub.");
// GCOV_EXCL_STOP
Expand Down Expand Up @@ -680,8 +682,7 @@ void SourceFile::collectAndPrintWarnings() { // NOLINT(misc-no-recursion)
}

bool SourceFile::haveAllDependantsBeenTypeChecked() const {
return std::all_of(dependants.begin(), dependants.end(),
[=](const SourceFile *dependant) { return dependant->typeCheckerRuns >= 1; });
return std::ranges::all_of(dependants, [](const SourceFile *dependant) { return dependant->totalTypeCheckerRuns >= 1; });
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/SourceFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class SourceFile {
GlobalResourceManager &resourceManager;
BS::synced_stream &tout;
uint8_t importedRuntimeModules = 0;
unsigned short typeCheckerRuns = 0;
unsigned short totalTypeCheckerRuns = 0;

// Private methods
bool haveAllDependantsBeenTypeChecked() const;
Expand Down
46 changes: 20 additions & 26 deletions src/global/RuntimeModuleManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,42 @@

namespace spice::compiler {

SourceFile *RuntimeModuleManager::requestModule(SourceFile *sourceFile, RuntimeModule requestedModule) {
// Check if the requested module is available already
bool available = isModuleAvailable(requestedModule);
SourceFile *RuntimeModuleManager::requestModule(SourceFile *parentSourceFile, RuntimeModule requestedModule) {
const std::string importName = resolveNamePair(requestedModule).importName;

// If not, try to make it available
if (!available)
available = addModule(sourceFile, requestedModule);
// Check if the requested module is available already, if not load it
auto rtFile = isModuleAvailable(requestedModule) ? modules.at(requestedModule) : loadModule(parentSourceFile, requestedModule);

// If the module is still not available, cancel here
if (!available)
return nullptr;
// Add the dependency to the parent source file
parentSourceFile->addDependency(rtFile, parentSourceFile->ast, importName, rtFile->filePath.string());
SourceFile *runtimeFile = parentSourceFile->dependencies.at(importName).first;
modules.emplace(requestedModule, runtimeFile);

// Merge the module name registry with the one of the source file
const ModuleNamePair names = resolveNamePair(requestedModule);
SourceFile *runtimeModuleFile = modules.at(requestedModule);
sourceFile->mergeNameRegistries(*runtimeModuleFile, names.importName);
parentSourceFile->mergeNameRegistries(*rtFile, importName);

// Tell the source file, that the requested runtime has been imported
sourceFile->importedRuntimeModules |= requestedModule;
parentSourceFile->importedRuntimeModules |= requestedModule;

return runtimeModuleFile;
return rtFile;
}

bool RuntimeModuleManager::isModuleAvailable(RuntimeModule requestedModule) const { return modules.contains(requestedModule); }

bool RuntimeModuleManager::addModule(SourceFile *parentSourceFile, RuntimeModule requestedModule) {
SourceFile *RuntimeModuleManager::loadModule(SourceFile *parentSourceFile, RuntimeModule requestedModule) {
const auto [importName, fileName] = resolveNamePair(requestedModule);

const std::filesystem::path filePath = FileUtil::getStdDir() / "runtime" / (std::string(fileName) + ".spice");
if (filePath == parentSourceFile->filePath)
return false;
assert(filePath != parentSourceFile->filePath);

const auto moduleSourceFile = resourceManager.createSourceFile(parentSourceFile, importName, filePath, true);
parentSourceFile->addDependency(moduleSourceFile, parentSourceFile->ast, importName, filePath.string());
// Instruct the global resource manager to create a new source file
SourceFile *moduleSourceFile = resourceManager.createSourceFile(parentSourceFile, importName, filePath, true);
moduleSourceFile->mainFile = false;

// Run frontend and type checker for runtime module source file
const auto runtimeFile = parentSourceFile->dependencies.at(importName).first;
runtimeFile->runFrontEnd();
runtimeFile->runTypeCheckerPre();
modules.emplace(requestedModule, runtimeFile);
// Run frontend and first type checker run for the loaded source file
moduleSourceFile->runFrontEnd();
moduleSourceFile->runTypeCheckerPre();

return true;
return moduleSourceFile;
}

ModuleNamePair RuntimeModuleManager::resolveNamePair(spice::compiler::RuntimeModule runtimeModule) {
Expand Down
4 changes: 2 additions & 2 deletions src/global/RuntimeModuleManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ class RuntimeModuleManager {
RuntimeModuleManager(const RuntimeModuleManager &) = delete;

// Public methods
SourceFile *requestModule(SourceFile *sourceFile, RuntimeModule requestedModule);
SourceFile *requestModule(SourceFile *parentSourceFile, RuntimeModule requestedModule);
[[nodiscard]] bool isModuleAvailable(RuntimeModule requestedModule) const;

private:
// Private methods
bool addModule(SourceFile *parentSourceFile, RuntimeModule requestedModule);
SourceFile *loadModule(SourceFile *parentSourceFile, RuntimeModule requestedModule);
static ModuleNamePair resolveNamePair(RuntimeModule requestedModule);

// Private members
Expand Down

0 comments on commit ea32753

Please sign in to comment.