Skip to content

Commit fa1cc5a

Browse files
bors[bot]Marwes
andauthored
Merge #854
854: fix: Gracefully error on concurrently loaded cyclic modules r=Marwes a=Marwes bors r+ Co-authored-by: Markus Westerlind <[email protected]>
2 parents 77aa832 + e6f1aa9 commit fa1cc5a

File tree

8 files changed

+94
-63
lines changed

8 files changed

+94
-63
lines changed

Cargo.lock

Lines changed: 40 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ futures = { version = "0.3.1", default-features = false }
4343
codespan = "0.9"
4444
codespan-reporting = "0.9"
4545
pin-project-lite = { version = "0.1", optional = true }
46-
salsa = { version = "0.14.0", package = "gluon-salsa" }
46+
salsa = { version = "0.14.2", package = "gluon-salsa" }
4747

4848
serde = { version = "1.0.0", optional = true }
4949
serde_state = { version = "0.4", optional = true }
@@ -85,7 +85,7 @@ pretty_assertions = "0.6"
8585
structopt = "0.3"
8686
tempfile = "3.0.4"
8787
tensile = { version = "0.6", features = ["tokio"] }
88-
tokio = { version = "0.2", features = ["macros", "rt-core", "rt-threaded"] }
88+
tokio = { version = "0.2", features = ["macros", "rt-core", "rt-threaded", "fs"] }
8989
walkdir = "2"
9090

9191
serde = "1.0.0"

src/import.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ pub(crate) trait ImportApi: Send + Sync {
183183
compiler: &mut ModuleCompiler<'_>,
184184
vm: &Thread,
185185
module_id: &Symbol,
186-
) -> Result<ArcType, (Option<ArcType>, MacroError)>;
186+
) -> Result<ArcType, (Option<ArcType>, crate::Error)>;
187187
fn snapshot(&self, thread: RootedThread) -> DatabaseSnapshot;
188188
fn fork(
189189
&mut self,
@@ -210,14 +210,14 @@ where
210210
compiler: &mut ModuleCompiler<'_>,
211211
vm: &Thread,
212212
module_id: &Symbol,
213-
) -> Result<ArcType, (Option<ArcType>, MacroError)> {
213+
) -> Result<ArcType, (Option<ArcType>, crate::Error)> {
214214
assert!(module_id.is_global());
215215
let modulename = module_id.name().definition_name();
216216

217217
self.importer
218218
.import(compiler, vm, &modulename)
219219
.await
220-
.map_err(|(t, err)| (t, MacroError::new(err)))
220+
.map_err(|(t, err)| (t, err))
221221
}
222222
fn snapshot(&self, thread: RootedThread) -> DatabaseSnapshot {
223223
Self::snapshot(self, thread)
@@ -542,9 +542,7 @@ where
542542
.map_err(|err| Error::String(err.to_string()))?;
543543
modulename
544544
}
545-
Expr::Literal(Literal::String(ref filename)) => {
546-
format!("@{}", filename_to_module(filename))
547-
}
545+
Expr::Literal(Literal::String(ref filename)) => filename_to_module(filename),
548546
_ => {
549547
return Err(Error::String(
550548
"Expected a string literal or path to import".into(),

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ pub trait ThreadExt: Send + Sync {
630630
db.add_module(module_name.clone(), input.into());
631631
}
632632
let mut db = vm.get_database();
633-
db.global(module_name).await.map(|_| ())
633+
db.import(module_name).await.map(|_| ())
634634
}
635635

636636
/// Loads `filename` and compiles and runs its input by calling `load_script`

src/query.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -439,18 +439,20 @@ fn recover_cycle<T>(
439439
cycle: &[String],
440440
module: &String,
441441
) -> StdResult<T, Error> {
442+
let mut cycle: Vec<_> = cycle
443+
.iter()
444+
.filter(|k| k.contains("CompileStorage(import("))
445+
.map(|k| {
446+
k.trim_matches(|c: char| c != '"')
447+
.trim_matches('"')
448+
.trim_start_matches('@')
449+
.to_string()
450+
})
451+
.collect();
452+
cycle.pop();
442453
Err(macros::Error::new(crate::import::Error::CyclicDependency(
443454
module.to_string(),
444-
cycle
445-
.iter()
446-
.filter(|k| k.contains("import"))
447-
.map(|k| {
448-
k.trim_matches(|c: char| c != '"')
449-
.trim_matches('"')
450-
.trim_start_matches('@')
451-
.to_string()
452-
})
453-
.collect(),
455+
cycle,
454456
))
455457
.into())
456458
}
@@ -638,14 +640,11 @@ async fn import(
638640
db: &mut dyn Compilation,
639641
modulename: String,
640642
) -> StdResult<TypedIdent<Symbol>, Error> {
643+
assert!(!modulename.starts_with('@'));
641644
let thread = db.thread().root_thread();
642645
let compiler = db.compiler();
643646

644-
let name = Symbol::from(if modulename.starts_with('@') {
645-
modulename.clone()
646-
} else {
647-
format!("@{}", modulename)
648-
});
647+
let name = Symbol::from(format!("@{}", modulename));
649648
let result = crate::get_import(&thread)
650649
.load_module(&mut ModuleCompiler::new(compiler), &thread, &name)
651650
.await

tests/fail/cyclic_dependency.glu

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
// ERROR Module 'tests.fail.cyclic_dependency' occurs in a cyclic dependency: `tests.fail.cyclic_dependency -> tests.fail.deps.cyclic_dependency2 -> tests.fail.cyclic_dependency`
12
let c = import! "tests/fail/deps/cyclic_dependency2.glu"
23
in 1

tests/fail/unwrap.glu

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// ERROR Option was None
12
let { Option, unwrap } = import! std.option
23

34
unwrap None

tests/main.rs

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
use std::{
2-
fs::File,
3-
io::{self, Read},
2+
io,
43
path::{Path, PathBuf},
54
};
65

76
use {
7+
anyhow::anyhow,
88
collect_mac::collect,
99
futures::{join, prelude::*, stream, task::SpawnExt},
1010
serde_derive::Deserialize,
1111
structopt::StructOpt,
1212
thiserror::Error,
13+
tokio::fs,
1314
};
1415

1516
use gluon::{
@@ -182,22 +183,36 @@ impl TestCase {
182183
}
183184

184185
async fn make_test<'t>(vm: &'t Thread, name: &str, filename: &Path) -> Result<TestCase, Error> {
185-
let mut file = File::open(&filename)?;
186-
let mut text = String::new();
187-
file.read_to_string(&mut text)?;
186+
let text = fs::read_to_string(filename).await?;
188187
let (De(test), _) = vm.run_expr_async(&name, &text).await?;
189188
Ok(test)
190189
}
191190

192-
async fn run_file<'t>(
193-
vm: &'t Thread,
194-
name: &str,
195-
filename: &Path,
196-
) -> Result<(OpaqueValue<RootedThread, Hole>, ArcType), Error> {
197-
let mut file = File::open(&filename)?;
198-
let mut text = String::new();
199-
file.read_to_string(&mut text)?;
200-
Ok(vm.run_expr_async(&name, &text).await?)
191+
async fn run_fail_test<'t>(vm: &'t Thread, name: &str, filename: &Path) -> Result<(), Error> {
192+
let source = fs::read_to_string(&filename).await?;
193+
let error_pattern = {
194+
let pat = "// ERROR";
195+
assert!(
196+
source.starts_with(pat),
197+
"Failure tests must have an error pattern to match against"
198+
);
199+
&source.lines().next().unwrap()[pat.len()..].trim()
200+
};
201+
match vm.load_script_async(&name, &source).await {
202+
Ok(err) => Err(anyhow!(
203+
"Expected test '{}' to fail\n{:?}",
204+
filename.to_str().unwrap(),
205+
err
206+
)
207+
.into()),
208+
Err(ref err) if !err.to_string().contains(error_pattern) => Err(anyhow!(
209+
"Error does not match the error pattern.\nExpected:\n\t`{}`\nActual:\n\t`{}`",
210+
error_pattern,
211+
err
212+
)
213+
.into()),
214+
Err(_) => Ok(()),
215+
}
201216
}
202217

203218
fn gather_doc_tests(expr: &SpannedExpr<Symbol>) -> Vec<(String, String)> {
@@ -279,9 +294,7 @@ async fn run_doc_tests<'t>(
279294
name: &str,
280295
filename: &Path,
281296
) -> Result<Vec<tensile::Test<Error>>, Error> {
282-
let mut file = File::open(&filename)?;
283-
let mut text = String::new();
284-
file.read_to_string(&mut text)?;
297+
let text = fs::read_to_string(filename).await?;
285298

286299
let (expr, _, _) = vm.extract_metadata(&name, &text).await?;
287300

@@ -386,15 +399,7 @@ async fn main_(options: &Opt) -> Result<(), Error> {
386399
tensile::test(
387400
name.clone(),
388401
tensile::Future(std::panic::AssertUnwindSafe(async move {
389-
match run_file(&vm, &name, &filename).await {
390-
Ok(err) => Err(format!(
391-
"Expected test '{}' to fail\n{:?}",
392-
filename.to_str().unwrap(),
393-
err.0,
394-
)
395-
.into()),
396-
Err(_) => Ok(()),
397-
}
402+
run_fail_test(&vm, &name, &filename).await
398403
})),
399404
)
400405
})

0 commit comments

Comments
 (0)