@@ -41,6 +41,8 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
41
41
42
42
static const _structClassName = 'Struct' ;
43
43
44
+ static const _unionClassName = 'Union' ;
45
+
44
46
/// The type system used to check types.
45
47
final TypeSystemImpl typeSystem;
46
48
@@ -49,41 +51,43 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
49
51
50
52
/// A flag indicating whether we are currently visiting inside a subclass of
51
53
/// `Struct` .
52
- bool inStruct = false ;
54
+ bool inCompound = false ;
53
55
54
- /// Subclass of `Struct` we are currently visiting, or `null` .
55
- ClassDeclaration ? struct ;
56
+ /// Subclass of `Struct` or `Union` we are currently visiting, or `null` .
57
+ ClassDeclaration ? compound ;
56
58
57
59
/// Initialize a newly created verifier.
58
60
FfiVerifier (this .typeSystem, this ._errorReporter);
59
61
60
62
@override
61
63
void visitClassDeclaration (ClassDeclaration node) {
62
- inStruct = false ;
63
- struct = null ;
64
+ inCompound = false ;
65
+ compound = null ;
64
66
// Only the Allocator, Opaque and Struct class may be extended.
65
67
var extendsClause = node.extendsClause;
66
68
if (extendsClause != null ) {
67
69
final TypeName superclass = extendsClause.superclass;
68
70
final ffiClass = superclass.ffiClass;
69
71
if (ffiClass != null ) {
70
72
final className = ffiClass.name;
71
- if (className == _structClassName) {
72
- inStruct = true ;
73
- struct = node;
73
+ if (className == _structClassName || className == _unionClassName ) {
74
+ inCompound = true ;
75
+ compound = node;
74
76
if (node.declaredElement! .isEmptyStruct) {
75
77
_errorReporter
76
78
.reportErrorForNode (FfiCode .EMPTY_STRUCT , node, [node.name]);
77
79
}
78
- _validatePackedAnnotation (node.metadata);
80
+ if (className == _structClassName) {
81
+ _validatePackedAnnotation (node.metadata);
82
+ }
79
83
} else if (className != _allocatorClassName &&
80
84
className != _opaqueClassName) {
81
85
_errorReporter.reportErrorForNode (
82
86
FfiCode .SUBTYPE_OF_FFI_CLASS_IN_EXTENDS ,
83
87
superclass.name,
84
88
[node.name.name, superclass.name.name]);
85
89
}
86
- } else if (superclass.isStructSubtype ) {
90
+ } else if (superclass.isCompoundSubtype ) {
87
91
_errorReporter.reportErrorForNode (
88
92
FfiCode .SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS ,
89
93
superclass,
@@ -101,7 +105,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
101
105
if (typename.ffiClass != null ) {
102
106
_errorReporter.reportErrorForNode (
103
107
subtypeOfFfiCode, typename, [node.name, typename.name]);
104
- } else if (typename.isStructSubtype ) {
108
+ } else if (typename.isCompoundSubtype ) {
105
109
_errorReporter.reportErrorForNode (
106
110
subtypeOfStructCode, typename, [node.name, typename.name]);
107
111
}
@@ -122,7 +126,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
122
126
}
123
127
}
124
128
125
- if (inStruct && node.declaredElement! .typeParameters.isNotEmpty) {
129
+ if (inCompound && node.declaredElement! .typeParameters.isNotEmpty) {
126
130
_errorReporter.reportErrorForNode (
127
131
FfiCode .GENERIC_STRUCT_SUBCLASS , node.name, [node.name]);
128
132
}
@@ -131,7 +135,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
131
135
132
136
@override
133
137
void visitConstructorFieldInitializer (ConstructorFieldInitializer node) {
134
- if (inStruct ) {
138
+ if (inCompound ) {
135
139
_errorReporter.reportErrorForNode (
136
140
FfiCode .FIELD_INITIALIZER_IN_STRUCT , node);
137
141
}
@@ -140,8 +144,8 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
140
144
141
145
@override
142
146
void visitFieldDeclaration (FieldDeclaration node) {
143
- if (inStruct ) {
144
- _validateFieldsInStruct (node);
147
+ if (inCompound ) {
148
+ _validateFieldsInCompound (node);
145
149
}
146
150
super .visitFieldDeclaration (node);
147
151
}
@@ -248,7 +252,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
248
252
case _PrimitiveDartType .none:
249
253
break ;
250
254
}
251
- if (nativeType.isStructSubtype ) {
255
+ if (nativeType.isCompoundSubtype ) {
252
256
return true ;
253
257
}
254
258
if (nativeType.isPointer) {
@@ -311,10 +315,10 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
311
315
final nativeArgumentType = nativeType.typeArguments.single;
312
316
return _isValidFfiNativeType (nativeArgumentType,
313
317
allowVoid: true , allowEmptyStruct: true , allowHandle: true ) ||
314
- nativeArgumentType.isStructSubtype ||
318
+ nativeArgumentType.isCompoundSubtype ||
315
319
nativeArgumentType.isNativeType;
316
320
}
317
- if (nativeType.isStructSubtype ) {
321
+ if (nativeType.isCompoundSubtype ) {
318
322
if (! allowEmptyStruct) {
319
323
if (nativeType.element.isEmptyStruct) {
320
324
// TODO(dartbug.com/36780): This results in an error message not
@@ -548,8 +552,8 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
548
552
}
549
553
550
554
/// Validate that the fields declared by the given [node] meet the
551
- /// requirements for fields within a struct class.
552
- void _validateFieldsInStruct (FieldDeclaration node) {
555
+ /// requirements for fields within a struct or union class.
556
+ void _validateFieldsInCompound (FieldDeclaration node) {
553
557
if (node.isStatic) {
554
558
return ;
555
559
}
@@ -576,18 +580,18 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
576
580
final arrayDimensions = declaredType.arrayDimensions;
577
581
_validateSizeOfAnnotation (fieldType, annotations, arrayDimensions);
578
582
final arrayElement = declaredType.arrayElementType;
579
- if (arrayElement.isStructSubtype ) {
583
+ if (arrayElement.isCompoundSubtype ) {
580
584
final elementClass = (arrayElement as InterfaceType ).element;
581
- _validatePackingNesting (struct ! .declaredElement! , elementClass,
585
+ _validatePackingNesting (compound ! .declaredElement! , elementClass,
582
586
errorNode: fieldType);
583
587
}
584
- } else if (declaredType.isStructSubtype ) {
588
+ } else if (declaredType.isCompoundSubtype ) {
585
589
final clazz = (declaredType as InterfaceType ).element;
586
590
if (clazz.isEmptyStruct) {
587
591
_errorReporter
588
592
.reportErrorForNode (FfiCode .EMPTY_STRUCT , node, [clazz.name]);
589
593
}
590
- _validatePackingNesting (struct ! .declaredElement! , clazz,
594
+ _validatePackingNesting (compound ! .declaredElement! , clazz,
591
595
errorNode: fieldType);
592
596
} else {
593
597
_errorReporter.reportErrorForNode (FfiCode .INVALID_FIELD_TYPE_IN_STRUCT ,
@@ -632,7 +636,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
632
636
if ((FT as FunctionType ).returnType.isVoid ||
633
637
R .isPointer ||
634
638
R .isHandle ||
635
- R .isStructSubtype ) {
639
+ R .isCompoundSubtype ) {
636
640
if (argCount != 1 ) {
637
641
_errorReporter.reportErrorForNode (
638
642
FfiCode .INVALID_EXCEPTION_VALUE , node.argumentList.arguments[1 ]);
@@ -975,7 +979,7 @@ extension on ClassElement {
975
979
return false ;
976
980
} else if (declaredType.isPointer) {
977
981
return false ;
978
- } else if (declaredType.isStructSubtype ) {
982
+ } else if (declaredType.isCompoundSubtype ) {
979
983
return false ;
980
984
} else if (declaredType.isArray) {
981
985
return false ;
@@ -1087,22 +1091,25 @@ extension on DartType {
1087
1091
return false ;
1088
1092
}
1089
1093
1090
- bool get isStruct {
1094
+ bool get isCompound {
1091
1095
final self = this ;
1092
1096
if (self is InterfaceType ) {
1093
1097
final element = self.element;
1094
- return element.name == FfiVerifier ._structClassName && element.isFfiClass;
1098
+ final name = element.name;
1099
+ return (name == FfiVerifier ._structClassName ||
1100
+ name == FfiVerifier ._unionClassName) &&
1101
+ element.isFfiClass;
1095
1102
}
1096
1103
return false ;
1097
1104
}
1098
1105
1099
1106
/// Returns `true` if this is a struct type, i.e. a subtype of `Struct` .
1100
- bool get isStructSubtype {
1107
+ bool get isCompoundSubtype {
1101
1108
final self = this ;
1102
1109
if (self is InterfaceType ) {
1103
1110
final superType = self.element.supertype;
1104
1111
if (superType != null ) {
1105
- return superType.isStruct ;
1112
+ return superType.isCompound ;
1106
1113
}
1107
1114
}
1108
1115
return false ;
@@ -1115,17 +1122,17 @@ extension on TypeName {
1115
1122
return name.staticElement.ffiClass;
1116
1123
}
1117
1124
1118
- /// Return `true` if this represents a subtype of `Struct` .
1119
- bool get isStructSubtype {
1125
+ /// Return `true` if this represents a subtype of `Struct` or `Union` .
1126
+ bool get isCompoundSubtype {
1120
1127
var element = name.staticElement;
1121
1128
if (element is ClassElement ) {
1122
- bool isStruct (InterfaceType ? type) {
1123
- return type != null && type.isStruct ;
1129
+ bool isCompound (InterfaceType ? type) {
1130
+ return type != null && type.isCompound ;
1124
1131
}
1125
1132
1126
- return isStruct (element.supertype) ||
1127
- element.interfaces.any (isStruct ) ||
1128
- element.mixins.any (isStruct );
1133
+ return isCompound (element.supertype) ||
1134
+ element.interfaces.any (isCompound ) ||
1135
+ element.mixins.any (isCompound );
1129
1136
}
1130
1137
return false ;
1131
1138
}
0 commit comments