@@ -696,7 +696,7 @@ public void flushStackIfNecessary() {
696
696
}
697
697
}
698
698
699
- protected void doFlushStack () {
699
+ private void doFlushStack () {
700
700
assert stackItems <= CollectionBits .KIND_MASK ;
701
701
if (collectionOnStack ) {
702
702
addOp (COLLECTION_ADD_STACK , typeBits | stackItems );
@@ -729,6 +729,27 @@ public boolean isEmpty() {
729
729
}
730
730
731
731
private class KwargsMergingDictCollector extends Collector {
732
+ /*
733
+ * Keyword arguments get evaluated in "groups", where a group is a contiguous sequence of
734
+ * named keyword arguments or a keyword-splat. For example, in
735
+ *
736
+ * f(a=2, b=3, **kws, c=4, d=5, **more_kws)
737
+ *
738
+ * there are 4 groups. Each group is evaluated and only then merged with the existing
739
+ * keyword arguments. The merge step is where duplicate keyword arguments are checked.
740
+ *
741
+ * A call can have an arbitrarily long sequence of named keyword arguments, so we flush them
742
+ * from the stack and collect them into an intermediate dict. We cannot eagerly merge them
743
+ * with the existing keyword arguments since that could trigger a duplication check before
744
+ * all of the arguments in the group have been evaluated. For example, in
745
+ *
746
+ * f(**{'a': 2}, a=3, b=4, ..., z=function_with_side_effects())
747
+ *
748
+ * we cannot merge "a=3" with the existing keywords dict (and consequently raise a
749
+ * TypeError) until we compute "z".
750
+ */
751
+ private boolean namedKeywordDictOnStack = false ;
752
+
732
753
public KwargsMergingDictCollector (OpCodes callOp ) {
733
754
super (CollectionBits .KIND_DICT );
734
755
/*
@@ -740,25 +761,66 @@ public KwargsMergingDictCollector(OpCodes callOp) {
740
761
}
741
762
742
763
@ Override
743
- protected void doFlushStack () {
744
- addOp (COLLECTION_FROM_STACK , typeBits | stackItems );
764
+ public void appendItem () {
765
+ stackItems += stackItemsPerItem ;
766
+ if (stackItems + stackItemsPerItem > CollectionBits .KIND_MASK ) {
767
+ collectIntoNamedKeywordDict ();
768
+ }
769
+ }
770
+
771
+ @ Override
772
+ public void flushStackIfNecessary () {
773
+ if (stackItems == 0 && !namedKeywordDictOnStack ) {
774
+ // Nothing pending to be merged.
775
+ return ;
776
+ }
777
+
778
+ if (stackItems > 0 ) {
779
+ collectIntoNamedKeywordDict ();
780
+ }
745
781
if (collectionOnStack ) {
782
+ // If there's already a collection on the stack, merge it with the dict we just
783
+ // finished creating.
746
784
addOp (KWARGS_DICT_MERGE );
747
785
}
748
786
collectionOnStack = true ;
787
+ namedKeywordDictOnStack = false ;
788
+ }
789
+
790
+ protected void collectIntoNamedKeywordDict () {
791
+ if (namedKeywordDictOnStack ) {
792
+ // Just add the keywords to the existing dict. Since we statically check for
793
+ // duplicate named keywords, we don't need to worry about duplicates in this dict.
794
+ addOp (COLLECTION_ADD_STACK , typeBits | stackItems );
795
+ } else {
796
+ // Create a new dict.
797
+ addOp (COLLECTION_FROM_STACK , typeBits | stackItems );
798
+ namedKeywordDictOnStack = true ;
799
+ }
749
800
stackItems = 0 ;
750
801
}
751
802
752
803
@ Override
753
804
public void appendCollection () {
754
805
assert stackItems == 0 ;
806
+ assert !namedKeywordDictOnStack ;
755
807
if (collectionOnStack ) {
756
808
addOp (KWARGS_DICT_MERGE );
757
809
} else {
758
810
addOp (COLLECTION_FROM_COLLECTION , typeBits );
759
811
}
760
812
collectionOnStack = true ;
761
813
}
814
+
815
+ @ Override
816
+ public void finishCollection () {
817
+ flushStackIfNecessary ();
818
+ }
819
+
820
+ @ Override
821
+ public boolean isEmpty () {
822
+ return stackItems == 0 || !namedKeywordDictOnStack || !collectionOnStack ;
823
+ }
762
824
}
763
825
764
826
private void collectIntoArray (ExprTy [] nodes , int bits , int alreadyOnStack ) {
0 commit comments