resolve regression in @mixin scoping

This commit is contained in:
ConnorSkees 2020-06-18 18:14:35 -04:00
parent 1f4698378d
commit 09a322f175
6 changed files with 43 additions and 14 deletions

View File

@ -1,6 +1,7 @@
# 0.9.1
- fix regression in which `@at-root` would panic when placed after a ruleset
- fix regression related to `@mixin` scoping and outer, local variables
- fix regression related to `@mixin` and `@function` scoping when combined with outer, local variables
# 0.9.0

View File

@ -25,6 +25,14 @@ impl<T> NeverEmptyVec<T> {
self.rest.last_mut().unwrap_or(&mut self.first)
}
pub fn first(&mut self) -> &T {
&self.first
}
pub fn first_mut(&mut self) -> &mut T {
&mut self.first
}
pub fn push(&mut self, value: T) {
self.rest.push(value)
}

View File

@ -3,7 +3,6 @@ use std::mem;
use codemap::Spanned;
use peekmore::PeekMore;
use super::{Parser, Stmt};
use crate::{
args::CallArgs,
atrule::Function,
@ -13,6 +12,8 @@ use crate::{
Token,
};
use super::{NeverEmptyVec, Parser, Stmt};
impl<'a> Parser<'a> {
pub(super) fn parse_function(&mut self) -> SassResult<()> {
if self.in_mixin {
@ -62,13 +63,12 @@ impl<'a> Parser<'a> {
pub fn eval_function(&mut self, mut function: Function, args: CallArgs) -> SassResult<Value> {
self.eval_fn_args(&mut function, args)?;
self.scopes.push(function.scope);
let mut return_value = Parser {
toks: &mut function.body.into_iter().peekmore(),
map: self.map,
path: self.path,
scopes: self.scopes,
scopes: &mut NeverEmptyVec::new(function.scope),
global_scope: self.global_scope,
super_selectors: self.super_selectors,
span_before: self.span_before,
@ -81,8 +81,6 @@ impl<'a> Parser<'a> {
}
.parse()?;
self.scopes.pop();
debug_assert!(return_value.len() <= 1);
match return_value
.pop()

View File

@ -6,13 +6,12 @@ use crate::{
args::{CallArgs, FuncArgs},
atrule::Mixin,
error::SassResult,
scope::Scope,
utils::read_until_closing_curly_brace,
value::Value,
Token,
};
use super::{Parser, Stmt};
use super::{NeverEmptyVec, Parser, Stmt};
impl<'a> Parser<'a> {
pub(super) fn parse_mixin(&mut self) -> SassResult<()> {
@ -41,7 +40,7 @@ impl<'a> Parser<'a> {
// this is blocked on figuring out just how to check for this. presumably we could have a check
// not when parsing initially, but rather when `@include`ing to see if an `@content` was found.
let mixin = Mixin::new(Scope::new(), args, body, false);
let mixin = Mixin::new(self.scopes.last().clone(), args, body, false);
if self.at_root {
self.global_scope.insert_mixin(name, mixin);
@ -97,13 +96,11 @@ impl<'a> Parser<'a> {
let mut mixin = self.scopes.last().get_mixin(name, self.global_scope)?;
self.eval_mixin_args(&mut mixin, args)?;
self.scopes.push(mixin.scope);
let body = Parser {
toks: &mut mixin.body,
map: self.map,
path: self.path,
scopes: self.scopes,
scopes: &mut NeverEmptyVec::new(mixin.scope),
global_scope: self.global_scope,
super_selectors: self.super_selectors,
span_before: self.span_before,
@ -116,8 +113,6 @@ impl<'a> Parser<'a> {
}
.parse()?;
self.scopes.pop();
Ok(body)
}

View File

@ -81,6 +81,11 @@ impl<'a> Parser<'a> {
scope.insert_var(ident.clone(), value.value.clone())?;
}
}
if self.scopes.first().var_exists_no_global(&ident) {
self.scopes
.first_mut()
.insert_var(ident.clone(), value.value.clone())?;
}
self.scopes.last_mut().insert_var(ident, value.value)?;
}
Ok(())

View File

@ -99,3 +99,25 @@ error!(
body_missing_closing_curly_brace,
"@function foo() {", "Error: expected \"}\"."
);
test!(
does_not_modify_local_variables,
"@function bar($color-name) {
@if $color-name==bar {
@error bar;
}
$color: bar;
@return null;
}
@function foo($a, $b) {
@return \"success!\";
}
a {
$color: foo;
color: foo(bar($color), bar($color));
}",
"a {\n color: \"success!\";\n}\n"
);