[ddc] Use exhaustive switch in `canEmitTypeAtTopLevel` Now that the `DartType` class hierarchy is sealed if-else chains over different `DartType`s can be replaced with exhaustive switch statements. Ensures the coverage of all types and provides compile time errors when new types are added without handling them instead of the awkward assertion logic that we had before. Issue: https://github.com/dart-lang/sdk/issues/53566 Change-Id: I5624dd53e8cb6f88d10a713e11e1488c28d67698 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/327020 Commit-Queue: Nicholas Shahan <nshahan@google.com> Reviewed-by: Anna Gringauze <annagrin@google.com>
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart index 3ad5256..a250446 100644 --- a/pkg/dev_compiler/lib/src/kernel/compiler.dart +++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -3308,33 +3308,40 @@ /// If we're emitting the type information for `foo`, we cannot refer to `C` /// yet, so we must evaluate foo's type lazily. bool _canEmitTypeAtTopLevel(DartType type) { - assert(isKnownDartTypeImplementor(type)); - if (type is InterfaceType) { - return !_pendingClasses!.contains(type.classNode) && - type.typeArguments.every(_canEmitTypeAtTopLevel); + switch (type) { + case InterfaceType(): + return !_pendingClasses!.contains(type.classNode) && + type.typeArguments.every(_canEmitTypeAtTopLevel); + case FutureOrType(): + return !_pendingClasses!.contains(_coreTypes.deprecatedFutureOrClass) && + _canEmitTypeAtTopLevel(type.typeArgument); + case FunctionType(): + // Generic functions are always safe to emit, because they're lazy until + // type arguments are applied. + if (type.typeParameters.isNotEmpty) return true; + return _canEmitTypeAtTopLevel(type.returnType) && + type.positionalParameters.every(_canEmitTypeAtTopLevel) && + type.namedParameters.every((n) => _canEmitTypeAtTopLevel(n.type)); + case RecordType(): + return type.positional.every(_canEmitTypeAtTopLevel) && + type.named.every((n) => _canEmitTypeAtTopLevel(n.type)); + case TypedefType(): + return type.typeArguments.every(_canEmitTypeAtTopLevel); + case ExtensionType(): + return _canEmitTypeAtTopLevel(type.typeErasure); + case DynamicType(): + case VoidType(): + case NeverType(): + case NullType(): + case IntersectionType(): + case TypeParameterType(): + case StructuralParameterType(): + return true; + case AuxiliaryType(): + throwUnsupportedAuxiliaryType(type); + case InvalidType(): + throwUnsupportedInvalidType(type); } - if (type is FutureOrType) { - return !_pendingClasses!.contains(_coreTypes.deprecatedFutureOrClass) && - _canEmitTypeAtTopLevel(type.typeArgument); - } - if (type is FunctionType) { - // Generic functions are always safe to emit, because they're lazy until - // type arguments are applied. - if (type.typeParameters.isNotEmpty) return true; - - return _canEmitTypeAtTopLevel(type.returnType) && - type.positionalParameters.every(_canEmitTypeAtTopLevel) && - type.namedParameters.every((n) => _canEmitTypeAtTopLevel(n.type)); - } - if (type is RecordType) { - return type.positional.every(_canEmitTypeAtTopLevel) && - type.named.every((n) => _canEmitTypeAtTopLevel(n.type)); - } - if (type is TypedefType) { - return type.typeArguments.every(_canEmitTypeAtTopLevel); - } - if (type is ExtensionType) return _canEmitTypeAtTopLevel(type.typeErasure); - return true; } /// Emits a Dart [type] into code.