From 78177e26de58c39efcd8a2aab03c067a4216a36a Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 22 Aug 2025 17:33:21 -0700 Subject: [PATCH 1/5] Make misplaced rest arguments a syntax error See sass/sass-spec#2072 --- CHANGELOG.md | 8 ++++++++ lib/src/parse/stylesheet.dart | 12 +++++++++++- pubspec.yaml | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32b1bdd06..04946298d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 1.92.0 + +* **Potentially breaking bug fix:** It's now a syntax error to write a rest + argument (`$arg...`) before a positional or named argument when calling a + function or mixin. This was always outside the specified syntax, and it + produced confusing and mostly incorrect results, so it's being changed without + a deprecation period. + ## 1.91.0 * **Potentially breaking change:** `meta.inspect()` (as well as other systems diff --git a/lib/src/parse/stylesheet.dart b/lib/src/parse/stylesheet.dart index efee015a4..6d44838e5 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -1836,7 +1836,9 @@ abstract class StylesheetParser extends Parser { var expression = expressionUntilComma(singleEquals: !mixin); whitespace(consumeNewlines: true); - if (expression is VariableExpression && scanner.scanChar($colon)) { + if (rest == null && + expression is VariableExpression && + scanner.scanChar($colon)) { whitespace(consumeNewlines: true); if (named.containsKey(expression.name)) { error("Duplicate argument.", expression.span); @@ -1858,6 +1860,14 @@ abstract class StylesheetParser extends Parser { "Positional arguments must come before keyword arguments.", expression.span, ); + } else if (rest != null) { + error( + ((expression is VariableExpression && scanner.peekChar() == $colon) + ? "Named" + : "Positional") + + " arguments must come before rest arguments.", + expression.span, + ); } else { positional.add(expression); } diff --git a/pubspec.yaml b/pubspec.yaml index efbcd7329..b656f1b88 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.91.0 +version: 1.92.0 description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass From 95295438202c12687ea566978c7bad8abac2ac4b Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 22 Aug 2025 17:42:06 -0700 Subject: [PATCH 2/5] Update pubspec/changelog --- CHANGELOG.md | 14 ++++++-------- pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04946298d..2314b44de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,3 @@ -## 1.92.0 - -* **Potentially breaking bug fix:** It's now a syntax error to write a rest - argument (`$arg...`) before a positional or named argument when calling a - function or mixin. This was always outside the specified syntax, and it - produced confusing and mostly incorrect results, so it's being changed without - a deprecation period. - ## 1.91.0 * **Potentially breaking change:** `meta.inspect()` (as well as other systems @@ -15,6 +7,12 @@ `meta.inspect()`, which is to provide full information about the structure of a Sass value. +* **Potentially breaking bug fix:** It's now a syntax error to write a rest + argument (`$arg...`) before a positional or named argument when calling a + function or mixin. This was always outside the specified syntax, and it + produced confusing and mostly incorrect results, so it's being changed without + a deprecation period. + ## 1.90.0 * Allow a `@forward`ed module to be loaded with a configuration when that module diff --git a/pubspec.yaml b/pubspec.yaml index b656f1b88..efbcd7329 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.92.0 +version: 1.91.0 description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass From 18f69720905382bf465b7baa01ad3a9d04958f4a Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 22 Aug 2025 18:23:38 -0700 Subject: [PATCH 3/5] Make this a deprecation rather than an error --- CHANGELOG.md | 10 ++++----- lib/src/deprecation.dart | 7 ++++++- lib/src/parse/stylesheet.dart | 38 +++++++++++++++++++++++++---------- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2314b44de..6e1819d81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,11 @@ `meta.inspect()`, which is to provide full information about the structure of a Sass value. -* **Potentially breaking bug fix:** It's now a syntax error to write a rest - argument (`$arg...`) before a positional or named argument when calling a - function or mixin. This was always outside the specified syntax, and it - produced confusing and mostly incorrect results, so it's being changed without - a deprecation period. +* Passing a rest argument (`$arg...`) before a positional or named argument when + calling a function or mixin is now deprecated. This was always outside the + specified syntax, but it was historically treated the same as passing the rest + argument at the end of the argument list whether or not that matched the + visual order of the arguments. ## 1.90.0 diff --git a/lib/src/deprecation.dart b/lib/src/deprecation.dart index dbda68937..17142dd36 100644 --- a/lib/src/deprecation.dart +++ b/lib/src/deprecation.dart @@ -15,7 +15,7 @@ enum Deprecation { // DO NOT EDIT. This section was generated from the language repo. // See tool/grind/generate_deprecations.dart for details. // - // Checksum: c57ab2eb07ab1df48581b8484ef9bdbad0ddceaa + // Checksum: 1c1efc2604729aea755453fefd1e8f56e100698e /// Deprecation for passing a string directly to meta.call(). callString('call-string', @@ -131,6 +131,11 @@ enum Deprecation { deprecatedIn: '1.88.0', description: 'Passing a relative url to compileString().'), + /// Deprecation for a rest parameter before a positional or named parameter. + misplacedRest('misplaced-rest', + deprecatedIn: '1.91.0', + description: 'A rest parameter before a positional or named parameter.'), + // END AUTOGENERATED CODE /// Used for deprecations coming from user-authored code. diff --git a/lib/src/parse/stylesheet.dart b/lib/src/parse/stylesheet.dart index 6d44838e5..93fcf03c1 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -15,6 +15,7 @@ import '../exception.dart'; import '../interpolation_buffer.dart'; import '../util/character.dart'; import '../utils.dart'; +import '../util/multi_span.dart'; import '../util/nullable.dart'; import '../value.dart'; import 'parser.dart'; @@ -1832,18 +1833,30 @@ abstract class StylesheetParser extends Parser { var named = {}; Expression? rest; Expression? keywordRest; + var emittedRestDeprecation = false; while (_lookingAtExpression()) { var expression = expressionUntilComma(singleEquals: !mixin); whitespace(consumeNewlines: true); - if (rest == null && - expression is VariableExpression && - scanner.scanChar($colon)) { + if (expression is VariableExpression && scanner.scanChar($colon)) { whitespace(consumeNewlines: true); if (named.containsKey(expression.name)) { error("Duplicate argument.", expression.span); } named[expression.name] = expressionUntilComma(singleEquals: !mixin); + + if (rest != null && !emittedRestDeprecation) { + emittedRestDeprecation = true; + warnings.add(( + deprecation: Deprecation.misplacedRest, + message: 'Named arguments must come before rest arguments.\n' + 'This will be an error in Dart Sass 2.0.0.', + span: MultiSpan( + scanner.spanFromPosition(expression.span.start.offset), + 'named argument', + {rest.span: 'rest argument'}) + )); + } } else if (scanner.scanChar($dot)) { scanner.expectChar($dot); scanner.expectChar($dot); @@ -1860,16 +1873,19 @@ abstract class StylesheetParser extends Parser { "Positional arguments must come before keyword arguments.", expression.span, ); - } else if (rest != null) { - error( - ((expression is VariableExpression && scanner.peekChar() == $colon) - ? "Named" - : "Positional") + - " arguments must come before rest arguments.", - expression.span, - ); } else { positional.add(expression); + + if (rest != null && !emittedRestDeprecation) { + emittedRestDeprecation = true; + warnings.add(( + deprecation: Deprecation.misplacedRest, + message: 'Positional arguments must come before rest arguments.\n' + 'This will be an error in Dart Sass 2.0.0.', + span: MultiSpan(expression.span, 'positional argument', + {rest.span: 'rest argument'}) + )); + } } whitespace(consumeNewlines: true); From 5ce537dc8fd4dc08bb83b461af5e293b2aa50fb8 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 22 Aug 2025 18:31:02 -0700 Subject: [PATCH 4/5] Poke CI From 3acff55fece13f96070d64d8a9a0ecb820d4e127 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 22 Aug 2025 18:56:23 -0700 Subject: [PATCH 5/5] Poke CI