@@ -436,11 +436,6 @@ pub struct UnsupportedSyntaxError {
436
436
pub kind : UnsupportedSyntaxErrorKind ,
437
437
pub range : TextRange ,
438
438
/// The target [`PythonVersion`] for which this error was detected.
439
- ///
440
- /// This is different from the version reported by the
441
- /// [`minimum_version`](UnsupportedSyntaxErrorKind::minimum_version) method, which is the
442
- /// earliest allowed version for this piece of syntax. The `target_version` is primarily used
443
- /// for user-facing error messages.
444
439
pub target_version : PythonVersion ,
445
440
}
446
441
@@ -457,6 +452,26 @@ pub enum UnsupportedSyntaxErrorKind {
457
452
Walrus ,
458
453
ExceptStar ,
459
454
455
+ /// Represents the use of a parenthesized keyword argument name after Python 3.8.
456
+ ///
457
+ /// ## Example
458
+ ///
459
+ /// From [BPO 34641] it sounds like this was only accidentally supported and was removed when
460
+ /// noticed. Code like this used to be valid:
461
+ ///
462
+ /// ```python
463
+ /// f((a)=1)
464
+ /// ```
465
+ ///
466
+ /// After Python 3.8, you have to omit the parentheses around `a`:
467
+ ///
468
+ /// ```python
469
+ /// f(a=1)
470
+ /// ```
471
+ ///
472
+ /// [BPO 34641]: https://github.com/python/cpython/issues/78822
473
+ ParenthesizedKeywordArgumentName ,
474
+
460
475
/// Represents the use of unparenthesized tuple unpacking in a `return` statement or `yield`
461
476
/// expression before Python 3.8.
462
477
///
@@ -603,6 +618,9 @@ impl Display for UnsupportedSyntaxError {
603
618
UnsupportedSyntaxErrorKind :: Match => "Cannot use `match` statement" ,
604
619
UnsupportedSyntaxErrorKind :: Walrus => "Cannot use named assignment expression (`:=`)" ,
605
620
UnsupportedSyntaxErrorKind :: ExceptStar => "Cannot use `except*`" ,
621
+ UnsupportedSyntaxErrorKind :: ParenthesizedKeywordArgumentName => {
622
+ "Cannot use parenthesized keyword argument name"
623
+ }
606
624
UnsupportedSyntaxErrorKind :: StarTuple ( StarTupleKind :: Return ) => {
607
625
"Cannot use iterable unpacking in return statements"
608
626
}
@@ -619,30 +637,65 @@ impl Display for UnsupportedSyntaxError {
619
637
"Cannot set default type for a type parameter"
620
638
}
621
639
} ;
640
+
622
641
write ! (
623
642
f,
624
- "{kind} on Python {} (syntax was added in Python { })" ,
643
+ "{kind} on Python {} (syntax was {changed })" ,
625
644
self . target_version,
626
- self . kind. minimum_version ( ) ,
645
+ changed = self . kind. changed_version ( ) ,
627
646
)
628
647
}
629
648
}
630
649
650
+ /// Represents the kind of change in Python syntax between versions.
651
+ enum Change {
652
+ Added ( PythonVersion ) ,
653
+ Removed ( PythonVersion ) ,
654
+ }
655
+
656
+ impl Display for Change {
657
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
658
+ match self {
659
+ Change :: Added ( version) => write ! ( f, "added in Python {version}" ) ,
660
+ Change :: Removed ( version) => write ! ( f, "removed in Python {version}" ) ,
661
+ }
662
+ }
663
+ }
664
+
631
665
impl UnsupportedSyntaxErrorKind {
632
- /// The earliest allowed version for the syntax associated with this error.
633
- pub const fn minimum_version ( & self ) -> PythonVersion {
666
+ /// Returns the Python version when the syntax associated with this error was changed, and the
667
+ /// type of [`Change`] (added or removed).
668
+ const fn changed_version ( self ) -> Change {
634
669
match self {
635
- UnsupportedSyntaxErrorKind :: Match => PythonVersion :: PY310 ,
636
- UnsupportedSyntaxErrorKind :: Walrus => PythonVersion :: PY38 ,
637
- UnsupportedSyntaxErrorKind :: ExceptStar => PythonVersion :: PY311 ,
638
- UnsupportedSyntaxErrorKind :: StarTuple ( _) => PythonVersion :: PY38 ,
639
- UnsupportedSyntaxErrorKind :: RelaxedDecorator => PythonVersion :: PY39 ,
640
- UnsupportedSyntaxErrorKind :: PositionalOnlyParameter => PythonVersion :: PY38 ,
641
- UnsupportedSyntaxErrorKind :: TypeParameterList => PythonVersion :: PY312 ,
642
- UnsupportedSyntaxErrorKind :: TypeAliasStatement => PythonVersion :: PY312 ,
643
- UnsupportedSyntaxErrorKind :: TypeParamDefault => PythonVersion :: PY313 ,
670
+ UnsupportedSyntaxErrorKind :: Match => Change :: Added ( PythonVersion :: PY310 ) ,
671
+ UnsupportedSyntaxErrorKind :: Walrus => Change :: Added ( PythonVersion :: PY38 ) ,
672
+ UnsupportedSyntaxErrorKind :: ExceptStar => Change :: Added ( PythonVersion :: PY311 ) ,
673
+ UnsupportedSyntaxErrorKind :: StarTuple ( _) => Change :: Added ( PythonVersion :: PY38 ) ,
674
+ UnsupportedSyntaxErrorKind :: RelaxedDecorator => Change :: Added ( PythonVersion :: PY39 ) ,
675
+ UnsupportedSyntaxErrorKind :: PositionalOnlyParameter => {
676
+ Change :: Added ( PythonVersion :: PY38 )
677
+ }
678
+ UnsupportedSyntaxErrorKind :: ParenthesizedKeywordArgumentName => {
679
+ Change :: Removed ( PythonVersion :: PY38 )
680
+ }
681
+ UnsupportedSyntaxErrorKind :: TypeParameterList => Change :: Added ( PythonVersion :: PY312 ) ,
682
+ UnsupportedSyntaxErrorKind :: TypeAliasStatement => Change :: Added ( PythonVersion :: PY312 ) ,
683
+ UnsupportedSyntaxErrorKind :: TypeParamDefault => Change :: Added ( PythonVersion :: PY313 ) ,
644
684
}
645
685
}
686
+
687
+ /// Returns whether or not this kind of syntax is unsupported on `target_version`.
688
+ pub ( crate ) fn is_unsupported ( self , target_version : PythonVersion ) -> bool {
689
+ match self . changed_version ( ) {
690
+ Change :: Added ( version) => target_version < version,
691
+ Change :: Removed ( version) => target_version >= version,
692
+ }
693
+ }
694
+
695
+ /// Returns `true` if this kind of syntax is supported on `target_version`.
696
+ pub ( crate ) fn is_supported ( self , target_version : PythonVersion ) -> bool {
697
+ !self . is_unsupported ( target_version)
698
+ }
646
699
}
647
700
648
701
#[ cfg( target_pointer_width = "64" ) ]
0 commit comments