Skip to content

Commit a95c5b8

Browse files
committed
Do variable index adjustments when accessing variables, not nodes
Doing this for variable *nodes* was breaking in extremely specific circumstances: * A null node is passed into setVariable() and, if source maps are enabled, recorded in _variableNodes. * Later on, getVariableNode() is called for that variable. Because that variable's node is null, it calls _getVariableNodeFromGlobalModule() even though the variable is actually defined. * _getVariableNodeFromGlobalModule() sets _lastVariableIndex to 0 on the assumption that the variable is undefined, which turns out to be incorrect in this specific case. The next commit will fix the issue where a null node can be passed into setVariable() when source maps are enabled, but it makes more sense to assign the variable index to 0 in the variable access anyway, since it happens first and isn't skipped when source maps are disabled.
1 parent 5709d90 commit a95c5b8

File tree

3 files changed

+42
-15
lines changed

3 files changed

+42
-15
lines changed

lib/src/async_environment.dart

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,12 @@ class AsyncEnvironment {
419419
}
420420

421421
index = _variableIndex(name);
422-
if (index == null) return _getVariableFromGlobalModule(name);
422+
if (index == null) {
423+
// There isn't a real variable defined as this index, but it will cause
424+
// [getVariable] to short-circuit and get to this function faster next
425+
// time the variable is accessed.
426+
return _getVariableFromGlobalModule(name);
427+
}
423428

424429
_lastVariableName = name;
425430
_lastVariableIndex = index;
@@ -476,12 +481,6 @@ class AsyncEnvironment {
476481
/// required, since some nodes need to do real work to manufacture a source
477482
/// span.
478483
AstNode _getVariableNodeFromGlobalModule(String name) {
479-
// There isn't a real variable defined as this index, but it will cause
480-
// [getVariable] to short-circuit and get to this function faster next time
481-
// the variable is accessed.
482-
_lastVariableName = name;
483-
_lastVariableIndex = 0;
484-
485484
if (_globalModules == null) return null;
486485

487486
// We don't need to worry about multiple modules defining the same variable,

lib/src/environment.dart

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// DO NOT EDIT. This file was generated from async_environment.dart.
66
// See tool/grind/synchronize.dart for details.
77
//
8-
// Checksum: f02d694ae04ee7fb2219d7930049480eda1fd734
8+
// Checksum: 76e7c2e929fc7d19390987069ff3a8c4b3fadfc5
99
//
1010
// ignore_for_file: unused_import
1111

@@ -426,7 +426,12 @@ class Environment {
426426
}
427427

428428
index = _variableIndex(name);
429-
if (index == null) return _getVariableFromGlobalModule(name);
429+
if (index == null) {
430+
// There isn't a real variable defined as this index, but it will cause
431+
// [getVariable] to short-circuit and get to this function faster next
432+
// time the variable is accessed.
433+
return _getVariableFromGlobalModule(name);
434+
}
430435

431436
_lastVariableName = name;
432437
_lastVariableIndex = index;
@@ -483,12 +488,6 @@ class Environment {
483488
/// required, since some nodes need to do real work to manufacture a source
484489
/// span.
485490
AstNode _getVariableNodeFromGlobalModule(String name) {
486-
// There isn't a real variable defined as this index, but it will cause
487-
// [getVariable] to short-circuit and get to this function faster next time
488-
// the variable is accessed.
489-
_lastVariableName = name;
490-
_lastVariableIndex = 0;
491-
492491
if (_globalModules == null) return null;
493492

494493
// We don't need to worry about multiple modules defining the same variable,

test/cli/shared.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,4 +538,33 @@ void sharedTests(
538538
});
539539
});
540540
});
541+
542+
test("doesn't unassign variables", () async {
543+
// This is a regression test for one of the strangest errors I've ever
544+
// encountered. Every bit of what's going on was necessary to reproduce it,
545+
// *including* running with source maps enabled, which is why it's here and
546+
// not in sass-spec.
547+
await d.file("input.scss", "a {@import 'downstream'}").create();
548+
await d.file("_downstream.scss", r"""
549+
@import 'midstream';
550+
551+
$b: $c;
552+
@mixin d($_) {}
553+
@include d($b);
554+
e {f: $b}
555+
""").create();
556+
await d.file("_midstream.scss", "@forward 'upstream'").create();
557+
await d.file("_upstream.scss", r"$c: g").create();
558+
559+
var sass = await runSass(["input.scss", "output.css"]);
560+
await sass.shouldExit(0);
561+
562+
await d.file("output.css", equalsIgnoringWhitespace("""
563+
a e {
564+
f: g;
565+
}
566+
567+
/*# sourceMappingURL=output.css.map */
568+
""")).validate();
569+
});
541570
}

0 commit comments

Comments
 (0)