Fix circular variable dependency error message (#909)

This commit is contained in:
Casey Rodarmor 2021-07-19 18:10:35 -07:00 committed by GitHub
parent 6cf3d204e6
commit 0fea73455b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 30 additions and 23 deletions

View File

@ -5,7 +5,6 @@ use CompilationErrorKind::*;
pub(crate) struct AssignmentResolver<'src: 'run, 'run> { pub(crate) struct AssignmentResolver<'src: 'run, 'run> {
assignments: &'run Table<'src, Assignment<'src>>, assignments: &'run Table<'src, Assignment<'src>>,
stack: Vec<&'src str>, stack: Vec<&'src str>,
seen: BTreeSet<&'src str>,
evaluated: BTreeSet<&'src str>, evaluated: BTreeSet<&'src str>,
} }
@ -14,9 +13,8 @@ impl<'src: 'run, 'run> AssignmentResolver<'src, 'run> {
assignments: &Table<'src, Assignment<'src>>, assignments: &Table<'src, Assignment<'src>>,
) -> CompilationResult<'src, ()> { ) -> CompilationResult<'src, ()> {
let mut resolver = AssignmentResolver { let mut resolver = AssignmentResolver {
stack: empty(), stack: Vec::new(),
seen: empty(), evaluated: BTreeSet::new(),
evaluated: empty(),
assignments, assignments,
}; };
@ -32,7 +30,6 @@ impl<'src: 'run, 'run> AssignmentResolver<'src, 'run> {
return Ok(()); return Ok(());
} }
self.seen.insert(name);
self.stack.push(name); self.stack.push(name);
if let Some(assignment) = self.assignments.get(name) { if let Some(assignment) = self.assignments.get(name) {
@ -53,6 +50,9 @@ impl<'src: 'run, 'run> AssignmentResolver<'src, 'run> {
token, token,
}); });
} }
self.stack.pop();
Ok(()) Ok(())
} }
@ -62,7 +62,7 @@ impl<'src: 'run, 'run> AssignmentResolver<'src, 'run> {
let variable = name.lexeme(); let variable = name.lexeme();
if self.evaluated.contains(variable) { if self.evaluated.contains(variable) {
Ok(()) Ok(())
} else if self.seen.contains(variable) { } else if self.stack.contains(&variable) {
let token = self.assignments[variable].name.token(); let token = self.assignments[variable].name.token();
self.stack.push(variable); self.stack.push(variable);
Err(token.error(CircularVariableDependency { Err(token.error(CircularVariableDependency {

View File

@ -41,21 +41,21 @@ impl Color {
pub(crate) fn auto() -> Self { pub(crate) fn auto() -> Self {
Self { Self {
use_color: UseColor::Auto, use_color: UseColor::Auto,
..default() ..Color::default()
} }
} }
pub(crate) fn always() -> Self { pub(crate) fn always() -> Self {
Self { Self {
use_color: UseColor::Always, use_color: UseColor::Always,
..default() ..Color::default()
} }
} }
pub(crate) fn never() -> Self { pub(crate) fn never() -> Self {
Self { Self {
use_color: UseColor::Never, use_color: UseColor::Never,
..default() ..Color::default()
} }
} }

View File

@ -33,9 +33,7 @@ pub(crate) use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
pub(crate) use crate::{config_error, setting}; pub(crate) use crate::{config_error, setting};
// functions // functions
pub(crate) use crate::{ pub(crate) use crate::{load_dotenv::load_dotenv, output::output, unindent::unindent};
default::default, empty::empty, load_dotenv::load_dotenv, output::output, unindent::unindent,
};
// traits // traits
pub(crate) use crate::{ pub(crate) use crate::{

View File

@ -1,3 +0,0 @@
pub(crate) fn default<T: Default>() -> T {
Default::default()
}

View File

@ -1,5 +0,0 @@
use crate::common::*;
pub(crate) fn empty<T, C: iter::FromIterator<T>>() -> C {
iter::empty().collect()
}

View File

@ -71,10 +71,8 @@ mod compiler;
mod config; mod config;
mod config_error; mod config_error;
mod count; mod count;
mod default;
mod delimiter; mod delimiter;
mod dependency; mod dependency;
mod empty;
mod enclosure; mod enclosure;
mod error; mod error;
mod error_result_ext; mod error_result_ext;

View File

@ -14,7 +14,7 @@ impl<'src: 'run, 'run> RecipeResolver<'src, 'run> {
assignments: &Table<'src, Assignment<'src>>, assignments: &Table<'src, Assignment<'src>>,
) -> CompilationResult<'src, Table<'src, Rc<Recipe<'src>>>> { ) -> CompilationResult<'src, Table<'src, Rc<Recipe<'src>>>> {
let mut resolver = RecipeResolver { let mut resolver = RecipeResolver {
resolved_recipes: empty(), resolved_recipes: Table::new(),
unresolved_recipes, unresolved_recipes,
assignments, assignments,
}; };

View File

@ -1410,6 +1410,25 @@ test! {
status: EXIT_FAILURE, status: EXIT_FAILURE,
} }
test! {
name: variable_circular_dependency_with_additional_variable,
justfile: "
a := ''
x := y
y := x
a:
",
args: ("a"),
stdout: "",
stderr: "error: Variable `x` depends on its own value: `x -> y -> x`
|
2 | x := y
| ^
",
status: EXIT_FAILURE,
}
test! { test! {
name: plus_variadic_recipe, name: plus_variadic_recipe,
justfile: " justfile: "