avoid deep recursion in extend

This commit is contained in:
Connor Skees 2021-07-04 11:32:19 -04:00
parent 8ea601ee43
commit 2b72a1fc0d
2 changed files with 31 additions and 6 deletions

View File

@ -239,7 +239,7 @@ impl Extender {
};
SelectorList {
components: self.trim(extended, |complex| self.originals.contains(complex)),
components: self.trim(extended, &|complex| self.originals.contains(complex)),
span: self.span,
}
}
@ -273,10 +273,12 @@ impl Extender {
let complex_has_line_break = complex.line_break;
let is_original = self.originals.contains(&complex);
for (i, component) in complex.components.iter().enumerate() {
if let ComplexSelectorComponent::Compound(component) = component {
if let Some(extended) =
self.extend_compound(component, extensions, media_query_context)
self.extend_compound(component, extensions, media_query_context, is_original)
{
if extended_not_expanded.is_none() {
extended_not_expanded = Some(
@ -361,13 +363,12 @@ impl Extender {
///
/// The `in_original` parameter indicates whether this is in an original
/// complex selector, meaning that `compound` should not be trimmed out.
// todo: `in_original` is actually obsolete and we should upstream its removal
// to dart-sass
fn extend_compound(
&mut self,
compound: &CompoundSelector,
extensions: Option<&HashMap<SimpleSelector, IndexMap<ComplexSelector, Extension>>>,
media_query_context: &Option<Vec<CssMediaQuery>>,
in_original: bool,
) -> Option<Vec<ComplexSelector>> {
// If there's more than one target and they all need to match, we track
// which targets are actually extended.
@ -524,7 +525,14 @@ impl Extender {
)
});
Some(unified_paths.flatten().flatten().collect())
let unified_paths: Vec<ComplexSelector> = unified_paths.flatten().flatten().collect();
Some(if in_original && self.mode != ExtendMode::Replace {
let original = unified_paths.first().cloned();
self.trim(unified_paths, &|complex| Some(complex) == original.as_ref())
} else {
self.trim(unified_paths, &|_| false)
})
}
fn extend_simple(
@ -781,7 +789,7 @@ impl Extender {
fn trim(
&self,
selectors: Vec<ComplexSelector>,
is_original: impl Fn(&ComplexSelector) -> bool,
is_original: &dyn Fn(&ComplexSelector) -> bool,
) -> Vec<ComplexSelector> {
// Avoid truly horrific quadratic behavior.
//

View File

@ -1880,6 +1880,23 @@ test!(
}",
":has(a >) b, :has(a >) :has(a >) :has(a >) b, :has(a >) :has(a >) :has(a >) b {\n color: red;\n}\n"
);
test!(
extend_after_target,
".a .b {
c: d;
}
.a.mod1, .a.mod2 {
@extend .a, .b;
}
.a.mod3, .a.mod4 {
@extend .a, .b;
}
.a.mod5, .a.mod6 {
@extend .a, .b;
}",
".a .b, .a .a.mod5, .a .a.mod6, .a .a.mod3, .a .a.mod4, .a .a.mod1, .a .a.mod2 {\n c: d;\n}\n"
);
error!(
extend_optional_keyword_not_complete,
"a {