@@ -59,6 +59,20 @@ extension on String {
59
59
}
60
60
}
61
61
62
+ extension on DeclaredType {
63
+ List <T > mapTypeParameters <T >(
64
+ T Function (bool isNullable, TypeUsage definedType) mapper,
65
+ ) {
66
+ final result = < T > [];
67
+ final offset = classDecl.allTypeParams.length - params.length;
68
+ for (var i = 0 ; i < classDecl.allTypeParams.length; ++ i) {
69
+ final param = i >= offset ? params[i - offset] : TypeUsage .object;
70
+ result.add (mapper (classDecl.allTypeParams[i].isNullable, param));
71
+ }
72
+ return result;
73
+ }
74
+ }
75
+
62
76
String _newLine ({int depth = 0 }) {
63
77
return '\n ${' ' * depth }' ;
64
78
}
@@ -732,6 +746,12 @@ $indent/// $comments
732
746
class _TypeGenerator extends TypeVisitor <String > {
733
747
final Resolver ? resolver;
734
748
749
+ /// Whether the top-type of the current type being visited is nullable.
750
+ ///
751
+ /// For example the top-type of `T` in `Foo<T extends Bar>` is `Bar` , this
752
+ /// will be true if `Bar` is nullable.
753
+ final bool isTopTypeNullable;
754
+
735
755
final bool forInterfaceImplementation;
736
756
737
757
/// Whether the generic types should be erased.
@@ -748,18 +768,21 @@ class _TypeGenerator extends TypeVisitor<String> {
748
768
this .typeErasure = false ,
749
769
this .includeNullability = true ,
750
770
this .arrayType = false ,
771
+ this .isTopTypeNullable = true ,
751
772
});
752
773
753
774
@override
754
775
String visitArrayType (ArrayType node) {
755
776
final innerType = node.elementType;
756
- final nullable = includeNullability && node.isNullable ? '?' : '' ;
777
+ final nullable =
778
+ includeNullability && node.isNullable && isTopTypeNullable ? '?' : '' ;
757
779
final typeGenerator = _TypeGenerator (
758
780
resolver,
759
781
forInterfaceImplementation: forInterfaceImplementation,
760
782
typeErasure: forInterfaceImplementation,
761
783
includeNullability: true ,
762
784
arrayType: true ,
785
+ isTopTypeNullable: true ,
763
786
);
764
787
if (innerType.kind == Kind .primitive) {
765
788
return '$_jni .J${innerType .accept (typeGenerator )}Array$nullable ' ;
@@ -769,44 +792,25 @@ class _TypeGenerator extends TypeVisitor<String> {
769
792
770
793
@override
771
794
String visitDeclaredType (DeclaredType node) {
772
- final nullable = includeNullability && node.isNullable ? '?' : '' ;
773
- if (node.classDecl.binaryName == 'java.lang.Object' ||
774
- node.classDecl.binaryName == 'java.lang.String' ) {
775
- return '$_jni .${node .classDecl .finalName }$nullable ' ;
795
+ if (node.classDecl.isObject) {
796
+ // The class is not generated, fall back to `JObject`.
797
+ return super .visitDeclaredType (node);
776
798
}
777
-
778
- // All type parameters of this type
779
- final allTypeParams = node.classDecl.allTypeParams
780
- .map ((typeParam) => typeParam.name)
781
- .toList ();
782
- // The ones that are declared.
783
- final typeGenerator = _TypeGenerator (
784
- resolver,
785
- forInterfaceImplementation: forInterfaceImplementation,
786
- typeErasure: forInterfaceImplementation,
787
- includeNullability: true ,
788
- arrayType: false ,
799
+ final nullable =
800
+ includeNullability && node.isNullable && isTopTypeNullable ? '?' : '' ;
801
+
802
+ final allTypeParams = node.mapTypeParameters (
803
+ (isNullable, definedType) {
804
+ return definedType.accept (_TypeGenerator (
805
+ resolver,
806
+ forInterfaceImplementation: forInterfaceImplementation,
807
+ typeErasure: forInterfaceImplementation,
808
+ includeNullability: true ,
809
+ arrayType: false ,
810
+ isTopTypeNullable: isNullable,
811
+ ));
812
+ },
789
813
);
790
- final definedTypeParams = node.params.accept (typeGenerator).toList ();
791
-
792
- // Replacing the declared ones. They come at the end.
793
- // The rest will be JObject.
794
- if (allTypeParams.length >= node.params.length) {
795
- final nullable = includeNullability ? '?' : '' ;
796
- allTypeParams.replaceRange (
797
- 0 ,
798
- allTypeParams.length - node.params.length,
799
- List .filled (
800
- allTypeParams.length - node.params.length,
801
- '$_jObject $nullable ' ,
802
- ),
803
- );
804
- allTypeParams.replaceRange (
805
- allTypeParams.length - node.params.length,
806
- allTypeParams.length,
807
- definedTypeParams,
808
- );
809
- }
810
814
811
815
final typeParams = allTypeParams.join (', ' ).encloseIfNotEmpty ('<' , '>' );
812
816
final prefix = resolver? .resolvePrefix (node.classDecl) ?? '' ;
@@ -826,7 +830,8 @@ class _TypeGenerator extends TypeVisitor<String> {
826
830
// TODO(https://github.com/dart-lang/native/issues/704): Tighten to
827
831
// typevar bounds instead.
828
832
{
829
- final nullable = includeNullability && node.isNullable ? '?' : '' ;
833
+ final nullable =
834
+ includeNullability && node.isNullable && isTopTypeNullable ? '?' : '' ;
830
835
if (typeErasure) {
831
836
return '$_jObject $nullable ' ;
832
837
}
@@ -849,15 +854,18 @@ class _TypeGenerator extends TypeVisitor<String> {
849
854
resolver,
850
855
arrayType: arrayType,
851
856
forInterfaceImplementation: forInterfaceImplementation,
852
- includeNullability: includeNullability && node.isNullable,
857
+ includeNullability:
858
+ includeNullability && node.isNullable && isTopTypeNullable,
853
859
typeErasure: typeErasure,
860
+ isTopTypeNullable: true ,
854
861
);
855
862
return node.extendsBound! .accept (typeGenerator);
856
863
}
857
864
858
865
@override
859
866
String visitNonPrimitiveType (ReferredType node) {
860
- final nullable = includeNullability ? '?' : '' ;
867
+ final nullable =
868
+ includeNullability && isTopTypeNullable && node.isNullable ? '?' : '' ;
861
869
return '$_jObject $nullable ' ;
862
870
}
863
871
}
@@ -873,6 +881,12 @@ class _TypeClass {
873
881
class _TypeClassGenerator extends TypeVisitor <_TypeClass > {
874
882
final bool isConst;
875
883
884
+ /// Whether the top-type of the current type being visited is nullable.
885
+ ///
886
+ /// For example the top-type of `T` in `Foo<T extends Bar>` is `Bar` , this
887
+ /// will be true if `Bar` is nullable.
888
+ final bool isTopTypeNullable;
889
+
876
890
/// Whether or not to return the equivalent boxed type class for primitives.
877
891
/// Only for interface implemetation.
878
892
final bool boxPrimitives;
@@ -895,6 +909,7 @@ class _TypeClassGenerator extends TypeVisitor<_TypeClass> {
895
909
this .forInterfaceImplementation = false ,
896
910
this .includeNullability = true ,
897
911
this .typeErasure = false ,
912
+ this .isTopTypeNullable = true ,
898
913
});
899
914
900
915
@override
@@ -907,6 +922,7 @@ class _TypeClassGenerator extends TypeVisitor<_TypeClass> {
907
922
forInterfaceImplementation: forInterfaceImplementation,
908
923
// Do type erasure for interface implementation.
909
924
typeErasure: forInterfaceImplementation,
925
+ isTopTypeNullable: true ,
910
926
),
911
927
);
912
928
final innerType = node.elementType.accept (
@@ -916,11 +932,13 @@ class _TypeClassGenerator extends TypeVisitor<_TypeClass> {
916
932
// Do type erasure for interface implementation.
917
933
typeErasure: forInterfaceImplementation,
918
934
arrayType: true ,
935
+ isTopTypeNullable: true ,
919
936
),
920
937
);
921
938
final ifConst = innerTypeClass.canBeConst && isConst ? 'const ' : '' ;
922
- final type =
923
- includeNullability && node.isNullable ? 'NullableType' : 'Type' ;
939
+ final type = includeNullability && node.isNullable && isTopTypeNullable
940
+ ? 'NullableType'
941
+ : 'Type' ;
924
942
if (node.elementType.kind == Kind .primitive) {
925
943
return _TypeClass (
926
944
'$ifConst $_jni .J${innerType }Array$type ()' ,
@@ -935,68 +953,54 @@ class _TypeClassGenerator extends TypeVisitor<_TypeClass> {
935
953
936
954
@override
937
955
_TypeClass visitDeclaredType (DeclaredType node) {
938
- final allTypeParams = node.classDecl.allTypeParams
939
- .map ((typeParam) => typeParam.name)
940
- .toList ();
941
-
942
- // The ones that are declared.
943
- final definedTypeClasses = node.params.accept (
944
- _TypeClassGenerator (
945
- resolver,
946
- isConst: false ,
947
- boxPrimitives: false ,
948
- forInterfaceImplementation: forInterfaceImplementation,
949
- typeErasure: forInterfaceImplementation,
950
- ),
956
+ if (node.classDecl.isObject) {
957
+ // The class is not generated, fall back to `JObject`.
958
+ return super .visitDeclaredType (node);
959
+ }
960
+ final allTypeClasses = node.mapTypeParameters (
961
+ (isNullable, definedType) {
962
+ return definedType.accept (_TypeClassGenerator (
963
+ resolver,
964
+ isConst: false ,
965
+ boxPrimitives: false ,
966
+ forInterfaceImplementation: forInterfaceImplementation,
967
+ typeErasure: forInterfaceImplementation,
968
+ isTopTypeNullable: isNullable,
969
+ ));
970
+ },
951
971
);
952
972
953
973
// Can be const if all the type parameters are defined and each of them are
954
974
// also const.
955
- final canBeConst =
956
- allTypeParams.isEmpty || definedTypeClasses.every ((e) => e.canBeConst);
975
+ final canBeConst = allTypeClasses.every ((e) => e.canBeConst);
957
976
958
- // Replacing the declared ones. They come at the end.
959
- // The rest will be `JObjectNullableType`.
960
- if (allTypeParams.length >= node.params.length) {
961
- allTypeParams.replaceRange (
962
- 0 ,
963
- allTypeParams.length - node.params.length,
964
- List .filled (
965
- allTypeParams.length - node.params.length,
966
- // Adding const to subexpressions if the entire expression is not
967
- // const.
968
- '${canBeConst ? '' : 'const ' }${_jObject }NullableType()' ,
969
- ),
970
- );
971
- allTypeParams.replaceRange (
972
- allTypeParams.length - node.params.length,
973
- allTypeParams.length,
974
- // Adding const to subexpressions if the entire expression is not const.
975
- definedTypeClasses.map (
976
- (param) =>
977
- '${param .canBeConst && !canBeConst ? 'const ' : '' }${param .name }' ,
978
- ),
979
- );
980
- }
977
+ // Add const to subexpressions if the entire expression is not const.
978
+ final allTypeParams = allTypeClasses
979
+ .map ((typeClass) =>
980
+ '${typeClass .canBeConst && !canBeConst ? 'const ' : '' }'
981
+ '${typeClass .name }' )
982
+ .toList ();
981
983
982
984
final args = allTypeParams.join (', ' );
983
985
final ifConst = isConst && canBeConst ? 'const ' : '' ;
984
- final type = includeNullability && node.isNullable
986
+ final type = includeNullability && node.isNullable && isTopTypeNullable
985
987
? node.classDecl.nullableTypeClassName
986
988
: node.classDecl.typeClassName;
987
- final typeArgs = node.classDecl.isObject
988
- ? ''
989
- : node.params
990
- .accept (
991
- _TypeGenerator (
992
- resolver,
993
- forInterfaceImplementation: forInterfaceImplementation,
994
- // Do type erasure for interface implementation.
995
- typeErasure: forInterfaceImplementation,
996
- ),
997
- )
998
- .join (', ' )
999
- .encloseIfNotEmpty ('<' , '>' );
989
+
990
+ final typeArgsList = node.mapTypeParameters (
991
+ (isNullable, definedType) {
992
+ return definedType.accept (
993
+ _TypeGenerator (
994
+ resolver,
995
+ forInterfaceImplementation: forInterfaceImplementation,
996
+ // Do type erasure for interface implementation.
997
+ typeErasure: forInterfaceImplementation,
998
+ isTopTypeNullable: isNullable,
999
+ ),
1000
+ );
1001
+ },
1002
+ );
1003
+ final typeArgs = typeArgsList.join (', ' ).encloseIfNotEmpty ('<' , '>' );
1000
1004
final prefix = resolver.resolvePrefix (node.classDecl);
1001
1005
return _TypeClass ('$ifConst $prefix $type $typeArgs ($args )' , canBeConst);
1002
1006
}
@@ -1012,10 +1016,13 @@ class _TypeClassGenerator extends TypeVisitor<_TypeClass> {
1012
1016
_TypeClass visitTypeVar (TypeVar node) {
1013
1017
// TODO(https://github.com/dart-lang/native/issues/704): Tighten to typevar
1014
1018
// bounds instead.
1015
- final type =
1016
- includeNullability && node.hasQuestionMark ? 'NullableType' : 'Type' ;
1019
+ final type = includeNullability && node.hasQuestionMark && isTopTypeNullable
1020
+ ? 'NullableType'
1021
+ : 'Type' ;
1017
1022
final convertToNullable =
1018
- includeNullability && node.hasQuestionMark ? '.nullableType' : '' ;
1023
+ includeNullability && node.hasQuestionMark && isTopTypeNullable
1024
+ ? '.nullableType'
1025
+ : '' ;
1019
1026
if (typeErasure) {
1020
1027
final ifConst = isConst ? 'const ' : '' ;
1021
1028
return _TypeClass ('$ifConst $_jObject $type ()' , true );
@@ -1044,18 +1051,21 @@ class _TypeClassGenerator extends TypeVisitor<_TypeClass> {
1044
1051
resolver,
1045
1052
boxPrimitives: boxPrimitives,
1046
1053
forInterfaceImplementation: forInterfaceImplementation,
1047
- includeNullability: includeNullability && node.isNullable,
1054
+ includeNullability:
1055
+ includeNullability && node.isNullable && isTopTypeNullable,
1048
1056
isConst: isConst,
1049
1057
typeErasure: typeErasure,
1058
+ isTopTypeNullable: true ,
1050
1059
);
1051
1060
return node.extendsBound! .accept (typeClassGenerator);
1052
1061
}
1053
1062
1054
1063
@override
1055
1064
_TypeClass visitNonPrimitiveType (ReferredType node) {
1056
1065
final ifConst = isConst ? 'const ' : '' ;
1057
- final type =
1058
- includeNullability && node.isNullable ? 'NullableType' : 'Type' ;
1066
+ final type = includeNullability && node.isNullable && isTopTypeNullable
1067
+ ? 'NullableType'
1068
+ : 'Type' ;
1059
1069
return _TypeClass ('$ifConst $_jObject $type ()' , true );
1060
1070
}
1061
1071
}
@@ -1667,7 +1677,8 @@ class _TypeVarLocator extends TypeVisitor<Map<String, List<OutsideInBuffer>>> {
1667
1677
@override
1668
1678
Map <String , List <OutsideInBuffer >> visitDeclaredType (DeclaredType node) {
1669
1679
if (node.classDecl.isObject) {
1670
- return {};
1680
+ // The class is not generated, fall back to `JObject`.
1681
+ return super .visitDeclaredType (node);
1671
1682
}
1672
1683
final offset = node.classDecl.allTypeParams.length - node.params.length;
1673
1684
final result = < String , List <OutsideInBuffer >> {};
0 commit comments