blob: 060aad1897510d3af44c94bcf80ab6d41608d79a [file] [log] [blame]
// 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,
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
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;
}