@@ -653,6 +653,17 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
653
653
inferrer.inferStatement (node.body);
654
654
}
655
655
656
+ DartType getSpreadElementType (DartType spreadType) {
657
+ if (spreadType is InterfaceType ) {
658
+ InterfaceType supertype = inferrer.typeSchemaEnvironment
659
+ .getTypeAsInstanceOf (spreadType, inferrer.coreTypes.iterableClass);
660
+ if (supertype == null ) return null ;
661
+ return supertype.typeArguments[0 ];
662
+ }
663
+ if (spreadType is DynamicType ) return const DynamicType ();
664
+ return null ;
665
+ }
666
+
656
667
void visitListLiteralJudgment (
657
668
ListLiteralJudgment node, DartType typeContext) {
658
669
var listClass = inferrer.coreTypes.listClass;
@@ -676,6 +687,8 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
676
687
} else {
677
688
inferredTypeArgument = node.typeArgument;
678
689
}
690
+ List <DartType > spreadTypes =
691
+ typeChecksNeeded ? new List <DartType >(node.expressions.length) : null ;
679
692
if (inferenceNeeded || typeChecksNeeded) {
680
693
for (int i = 0 ; i < node.expressions.length; ++ i) {
681
694
Expression judgment = node.expressions[i];
@@ -689,30 +702,12 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
689
702
if (inferenceNeeded) {
690
703
formalTypes.add (listType.typeArguments[0 ]);
691
704
}
692
- if (spreadType is InterfaceType ) {
693
- InterfaceType iterableType = inferrer.typeSchemaEnvironment
694
- .getTypeAsInstanceOf (
695
- spreadType, inferrer.coreTypes.iterableClass);
696
- if (iterableType != null ) {
697
- actualTypes.add (iterableType.typeArguments[0 ]);
698
- } else {
699
- inferrer.helper.buildProblem (
700
- templateSpreadTypeMismatch.withArguments (spreadType),
701
- judgment.expression.fileOffset,
702
- 1 );
703
- // Use 'dynamic' for error recovery.
704
- actualTypes.add (const DynamicType ());
705
- }
706
- } else if (spreadType is DynamicType ) {
707
- actualTypes.add (const DynamicType ());
708
- } else {
709
- inferrer.helper.buildProblem (
710
- templateSpreadTypeMismatch.withArguments (spreadType),
711
- judgment.expression.fileOffset,
712
- 1 );
713
- // Use 'dynamic' for error recovery.
714
- actualTypes.add (const DynamicType ());
705
+ if (typeChecksNeeded) {
706
+ spreadTypes[i] = spreadType;
715
707
}
708
+ // Use 'dynamic' for error recovery.
709
+ actualTypes
710
+ .add (getSpreadElementType (spreadType) ?? const DynamicType ());
716
711
} else {
717
712
inferrer.inferExpression (judgment, inferredTypeArgument,
718
713
inferenceNeeded || typeChecksNeeded,
@@ -742,9 +737,44 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
742
737
}
743
738
if (typeChecksNeeded) {
744
739
for (int i = 0 ; i < node.expressions.length; i++ ) {
745
- inferrer.ensureAssignable (node.typeArgument, actualTypes[i],
746
- node.expressions[i], node.expressions[i].fileOffset,
747
- isVoidAllowed: node.typeArgument is VoidType );
740
+ Expression item = node.expressions[i];
741
+ if (item is SpreadElement ) {
742
+ DartType spreadType = spreadTypes[i];
743
+ DartType spreadElementType = getSpreadElementType (spreadType);
744
+ if (spreadElementType == null ) {
745
+ node.replaceChild (
746
+ node.expressions[i],
747
+ inferrer.helper.desugarSyntheticExpression (inferrer.helper
748
+ .buildProblem (
749
+ templateSpreadTypeMismatch.withArguments (spreadType),
750
+ item.expression.fileOffset,
751
+ 1 )));
752
+ } else if (spreadType is DynamicType ) {
753
+ inferrer.ensureAssignable (inferrer.coreTypes.iterableClass.rawType,
754
+ spreadType, item.expression, item.expression.fileOffset);
755
+ } else if (spreadType is InterfaceType ) {
756
+ if (spreadType.classNode == inferrer.coreTypes.nullClass) {
757
+ // TODO(dmitryas): Handle this case when null-aware spreads are
758
+ // supported by the parser.
759
+ } else {
760
+ if (! inferrer.isAssignable (
761
+ node.typeArgument, spreadElementType)) {
762
+ node.replaceChild (
763
+ node.expressions[i],
764
+ inferrer.helper.desugarSyntheticExpression (inferrer.helper
765
+ .buildProblem (
766
+ templateSpreadElementTypeMismatch.withArguments (
767
+ spreadElementType, node.typeArgument),
768
+ item.expression.fileOffset,
769
+ 1 )));
770
+ }
771
+ }
772
+ }
773
+ } else {
774
+ inferrer.ensureAssignable (
775
+ node.typeArgument, actualTypes[i], item, item.fileOffset,
776
+ isVoidAllowed: node.typeArgument is VoidType );
777
+ }
748
778
}
749
779
}
750
780
node.inferredType = new InterfaceType (listClass, [inferredTypeArgument]);
@@ -755,8 +785,6 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
755
785
inferred: true );
756
786
}
757
787
758
- // Now, compile non-const list literals to block expressions if they
759
- // contain any spread or control-flow elements.
760
788
return null ;
761
789
}
762
790
@@ -1141,6 +1169,8 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
1141
1169
} else {
1142
1170
inferredTypeArgument = node.typeArgument;
1143
1171
}
1172
+ List <DartType > spreadTypes =
1173
+ typeChecksNeeded ? new List <DartType >(node.expressions.length) : null ;
1144
1174
if (inferenceNeeded || typeChecksNeeded) {
1145
1175
for (int i = 0 ; i < node.expressions.length; ++ i) {
1146
1176
Expression judgment = node.expressions[i];
@@ -1154,35 +1184,12 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
1154
1184
if (inferenceNeeded) {
1155
1185
formalTypes.add (setType.typeArguments[0 ]);
1156
1186
}
1157
- if (spreadType is InterfaceType ) {
1158
- InterfaceType iterableType = inferrer.typeSchemaEnvironment
1159
- .getTypeAsInstanceOf (
1160
- spreadType, inferrer.coreTypes.iterableClass);
1161
- if (iterableType != null ) {
1162
- actualTypes.add (iterableType.typeArguments[0 ]);
1163
- } else {
1164
- inferrer.helper.buildProblem (
1165
- templateSpreadTypeMismatch.withArguments (spreadType),
1166
- judgment.expression.fileOffset,
1167
- 1 );
1168
- // Use 'dynamic' for error recovery.
1169
- actualTypes.add (const DynamicType ());
1170
- }
1171
- } else if (spreadType is DynamicType ) {
1172
- actualTypes.add (const DynamicType ());
1173
- } else {
1174
- inferrer.helper.buildProblem (
1175
- templateSpreadTypeMismatch.withArguments (spreadType),
1176
- judgment.expression.fileOffset,
1177
- 1 );
1178
- // Use 'dynamic' for error recovery.
1179
- actualTypes.add (const DynamicType ());
1187
+ if (typeChecksNeeded) {
1188
+ spreadTypes[i] = spreadType;
1180
1189
}
1181
-
1182
- node.replaceChild (
1183
- judgment,
1184
- InvalidExpression ('unimplemented spread element' )
1185
- ..fileOffset = node.fileOffset);
1190
+ // Use 'dynamic' for error recovery.
1191
+ actualTypes
1192
+ .add (getSpreadElementType (spreadType) ?? const DynamicType ());
1186
1193
} else {
1187
1194
inferrer.inferExpression (judgment, inferredTypeArgument,
1188
1195
inferenceNeeded || typeChecksNeeded,
@@ -1212,9 +1219,57 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
1212
1219
}
1213
1220
if (typeChecksNeeded) {
1214
1221
for (int i = 0 ; i < node.expressions.length; i++ ) {
1215
- inferrer.ensureAssignable (node.typeArgument, actualTypes[i],
1216
- node.expressions[i], node.expressions[i].fileOffset,
1217
- isVoidAllowed: node.typeArgument is VoidType );
1222
+ Expression item = node.expressions[i];
1223
+ if (item is SpreadElement ) {
1224
+ // TODO(dmitrayas): Remove this flag and all related uses of it
1225
+ // when the desugaring is implemented.
1226
+ bool replaced = false ;
1227
+
1228
+ DartType spreadType = spreadTypes[i];
1229
+ DartType spreadElementType = getSpreadElementType (spreadType);
1230
+ if (spreadElementType == null ) {
1231
+ node.replaceChild (
1232
+ node.expressions[i],
1233
+ inferrer.helper.desugarSyntheticExpression (inferrer.helper
1234
+ .buildProblem (
1235
+ templateSpreadTypeMismatch.withArguments (spreadType),
1236
+ item.expression.fileOffset,
1237
+ 1 )));
1238
+ replaced = true ;
1239
+ } else if (spreadType is DynamicType ) {
1240
+ inferrer.ensureAssignable (inferrer.coreTypes.iterableClass.rawType,
1241
+ spreadType, item.expression, item.expression.fileOffset);
1242
+ } else if (spreadType is InterfaceType ) {
1243
+ if (spreadType.classNode == inferrer.coreTypes.nullClass) {
1244
+ // TODO(dmitryas): Handle this case when null-aware spreads are
1245
+ // supported by the parser.
1246
+ } else {
1247
+ if (! inferrer.isAssignable (
1248
+ node.typeArgument, spreadElementType)) {
1249
+ node.replaceChild (
1250
+ node.expressions[i],
1251
+ inferrer.helper.desugarSyntheticExpression (inferrer.helper
1252
+ .buildProblem (
1253
+ templateSpreadElementTypeMismatch.withArguments (
1254
+ spreadElementType, node.typeArgument),
1255
+ item.expression.fileOffset,
1256
+ 1 )));
1257
+ replaced = true ;
1258
+ }
1259
+ }
1260
+ }
1261
+
1262
+ if (! replaced) {
1263
+ node.replaceChild (
1264
+ node.expressions[i],
1265
+ new InvalidExpression ('unimplemented spread element' )
1266
+ ..fileOffset = node.expressions[i].fileOffset);
1267
+ }
1268
+ } else {
1269
+ inferrer.ensureAssignable (node.typeArgument, actualTypes[i],
1270
+ node.expressions[i], node.expressions[i].fileOffset,
1271
+ isVoidAllowed: node.typeArgument is VoidType );
1272
+ }
1218
1273
}
1219
1274
}
1220
1275
node.inferredType = new InterfaceType (setClass, [inferredTypeArgument]);
0 commit comments