| // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE.md file. |
| |
| import 'package:kernel/ast.dart' |
| show |
| DartType, |
| DartTypeVisitor, |
| DartTypeVisitor1, |
| FunctionType, |
| InterfaceType, |
| TypedefType, |
| Visitor; |
| |
| import 'package:kernel/import_table.dart' show ImportTable; |
| |
| import 'package:kernel/text/ast_to_text.dart' |
| show Annotator, NameSystem, Printer, globalDebuggingNames; |
| |
| /// Determines whether a type schema contains `?` somewhere inside it. |
| bool isKnown(DartType schema) => schema.accept(new _IsKnownVisitor()); |
| |
| /// Converts a [DartType] to a string, representing the unknown type as `?`. |
| String typeSchemaToString(DartType schema) { |
| StringBuffer buffer = new StringBuffer(); |
| new TypeSchemaPrinter(buffer, syntheticNames: globalDebuggingNames) |
| .writeNode(schema); |
| return '$buffer'; |
| } |
| |
| /// Extension of [Printer] that represents the unknown type as `?`. |
| class TypeSchemaPrinter extends Printer implements TypeSchemaVisitor<Null> { |
| TypeSchemaPrinter(StringSink sink, |
| {NameSystem syntheticNames, |
| bool showExternal, |
| bool showOffsets: false, |
| ImportTable importTable, |
| Annotator annotator}) |
| : super(sink, |
| syntheticNames: syntheticNames, |
| showExternal: showExternal, |
| showOffsets: showOffsets, |
| importTable: importTable, |
| annotator: annotator); |
| |
| @override |
| visitUnknownType(UnknownType node) { |
| writeWord('?'); |
| } |
| } |
| |
| /// Extension of [DartTypeVisitor] which can visit [UnknownType]. |
| class TypeSchemaVisitor<R> extends DartTypeVisitor<R> { |
| /// Called when [UnknownType] is visited. |
| R visitUnknownType(UnknownType node) => defaultDartType(node); |
| } |
| |
| /// The unknown type (denoted `?`) is an object which can appear anywhere that |
| /// a type is expected. It represents a component of a type which has not yet |
| /// been fixed by inference. |
| /// |
| /// The unknown type cannot appear in programs or in final inferred types: it is |
| /// purely part of the local inference process. |
| class UnknownType extends DartType { |
| const UnknownType(); |
| |
| bool operator ==(Object other) { |
| // This class doesn't have any fields so all instances of `UnknownType` are |
| // equal. |
| return other is UnknownType; |
| } |
| |
| @override |
| accept(DartTypeVisitor v) { |
| if (v is TypeSchemaVisitor) { |
| return v.visitUnknownType(this); |
| } else { |
| // Note: in principle it seems like this should throw, since any visitor |
| // that operates on a type schema ought to inherit from TypeSchemaVisitor. |
| // However, that would make it impossible to use toString() on any type |
| // schema, since toString() uses the kernel's Printer visitor, which can't |
| // possibly inherit from TypeSchemaVisitor since it's inside kernel. |
| return v.defaultDartType(this); |
| } |
| } |
| |
| @override |
| accept1(DartTypeVisitor1 v, arg) => v.defaultDartType(this, arg); |
| |
| @override |
| visitChildren(Visitor v) {} |
| } |
| |
| /// Visitor that computes [isKnown]. |
| class _IsKnownVisitor extends TypeSchemaVisitor<bool> { |
| @override |
| bool defaultDartType(DartType node) => true; |
| |
| @override |
| bool visitFunctionType(FunctionType node) { |
| if (!node.returnType.accept(this)) return false; |
| for (var parameterType in node.positionalParameters) { |
| if (!parameterType.accept(this)) return false; |
| } |
| for (var namedParameterType in node.namedParameters) { |
| if (!namedParameterType.type.accept(this)) return false; |
| } |
| return true; |
| } |
| |
| @override |
| bool visitInterfaceType(InterfaceType node) { |
| for (var typeArgument in node.typeArguments) { |
| if (!typeArgument.accept(this)) return false; |
| } |
| return true; |
| } |
| |
| @override |
| bool visitTypedefType(TypedefType node) { |
| for (var typeArgument in node.typeArguments) { |
| if (!typeArgument.accept(this)) return false; |
| } |
| return true; |
| } |
| |
| @override |
| bool visitUnknownType(UnknownType node) => false; |
| } |