blob: 4b6e58c59a1a937e1ccea76392d5be788efee482 [file] [log] [blame]
// Copyright (c) 2013, 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 file.
library type_test_helper;
import 'dart:async';
import 'package:expect/expect.dart';
import 'package:compiler/src/common/resolution.dart';
import 'package:compiler/src/common_elements.dart';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/elements/resolution_types.dart';
import 'package:compiler/src/elements/types.dart';
import 'package:compiler/src/compiler.dart' show Compiler;
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/elements/elements.dart'
show Element, MemberElement, ClassElement, LibraryElement, TypedefElement;
import 'package:compiler/src/world.dart' show ClosedWorld;
import 'compiler_helper.dart' as mock;
import 'memory_compiler.dart' as memory;
import 'kernel/compiler_helper.dart' as dill;
DartType instantiate(Entity element, List<DartType> arguments) {
if (element is ClassElement) {
return new ResolutionInterfaceType(element, arguments);
} else if (element is ClassEntity) {
return new InterfaceType(element, arguments);
} else {
assert(element is TypedefElement);
return new ResolutionTypedefType(element, arguments);
}
}
enum CompileMode { mock, memory, dill }
class TypeEnvironment {
final Compiler compiler;
final bool testBackendWorld;
Resolution get resolution => compiler.resolution;
Types get types => resolution.types;
static Future<TypeEnvironment> create(String source,
{CompileMode compileMode: CompileMode.mock,
bool useDillCompiler: false,
bool expectNoErrors: false,
bool expectNoWarningsOrErrors: false,
bool stopAfterTypeInference: false,
String mainSource,
bool testBackendWorld: false}) async {
Uri uri;
Compiler compiler;
if (mainSource != null) {
stopAfterTypeInference = true;
}
if (testBackendWorld) {
stopAfterTypeInference = true;
assert(mainSource != null);
}
if (mainSource == null) {
source = '''import 'dart:async';
main() {}
$source''';
} else {
source = '$mainSource\n$source';
}
memory.DiagnosticCollector collector;
if (compileMode == CompileMode.dill) {
collector = new memory.DiagnosticCollector();
uri = Uri.parse('memory:main.dart');
compiler = await dill.compileWithDill(
entryPoint: uri,
memorySourceFiles: {'main.dart': source},
diagnosticHandler: collector,
options: stopAfterTypeInference
? [Flags.disableTypeInference]
: [
Flags.disableTypeInference,
Flags.analyzeAll,
Flags.analyzeOnly
],
beforeRun: (Compiler compiler) {
compiler.stopAfterTypeInference = stopAfterTypeInference;
});
} else {
if (compileMode == CompileMode.mock) {
uri = new Uri(scheme: 'source');
mock.MockCompiler mockCompiler = mock.compilerFor(source, uri,
analyzeAll: !stopAfterTypeInference,
analyzeOnly: !stopAfterTypeInference);
mockCompiler.diagnosticHandler =
mock.createHandler(mockCompiler, source);
collector = mockCompiler.diagnosticCollector;
compiler = mockCompiler;
} else {
collector = new memory.DiagnosticCollector();
uri = Uri.parse('memory:main.dart');
compiler = memory.compilerFor(
entryPoint: uri,
memorySourceFiles: {'main.dart': source},
diagnosticHandler: collector,
options: stopAfterTypeInference
? []
: [Flags.analyzeAll, Flags.analyzeOnly]);
}
compiler.stopAfterTypeInference = stopAfterTypeInference;
await compiler.run(uri);
}
if (expectNoErrors || expectNoWarningsOrErrors) {
var errors = collector.errors;
Expect.isTrue(errors.isEmpty, 'Unexpected errors: ${errors}');
}
if (expectNoWarningsOrErrors) {
var warnings = collector.warnings;
Expect.isTrue(warnings.isEmpty, 'Unexpected warnings: ${warnings}');
}
return new TypeEnvironment._(compiler, testBackendWorld: testBackendWorld);
}
TypeEnvironment._(Compiler this.compiler, {this.testBackendWorld: false});
ElementEnvironment get elementEnvironment {
if (testBackendWorld) {
return compiler.backendClosedWorldForTesting.elementEnvironment;
} else {
return compiler.frontendStrategy.elementEnvironment;
}
}
Element getElement(String name) {
LibraryElement mainApp = elementEnvironment.mainLibrary;
dynamic element = mainApp.find(name);
Expect.isNotNull(element);
if (element.isClass) {
element.ensureResolved(compiler.resolution);
} else if (element.isTypedef) {
element.computeType(compiler.resolution);
}
return element;
}
ClassEntity getClass(String name) {
LibraryEntity mainLibrary = elementEnvironment.mainLibrary;
ClassEntity element = elementEnvironment.lookupClass(mainLibrary, name);
Expect.isNotNull(element);
if (element is ClassElement) {
element.ensureResolved(compiler.resolution);
}
return element;
}
ResolutionDartType getElementType(String name) {
dynamic element = getElement(name);
return element.computeType(compiler.resolution);
}
ResolutionDartType operator [](String name) {
if (name == 'dynamic') return const ResolutionDynamicType();
if (name == 'void') return const ResolutionVoidType();
return getElementType(name);
}
ResolutionDartType getMemberType(ClassElement element, String name) {
MemberElement member = element.localLookup(name);
return member.computeType(compiler.resolution);
}
bool isSubtype(ResolutionDartType T, ResolutionDartType S) {
return types.isSubtype(T, S);
}
bool isMoreSpecific(ResolutionDartType T, ResolutionDartType S) {
return types.isMoreSpecific(T, S);
}
ResolutionDartType computeLeastUpperBound(
ResolutionDartType T, ResolutionDartType S) {
return types.computeLeastUpperBound(T, S);
}
ResolutionDartType flatten(ResolutionDartType T) {
return types.flatten(T);
}
ResolutionFunctionType functionType(
ResolutionDartType returnType, List<ResolutionDartType> parameters,
{List<ResolutionDartType> optionalParameters:
const <ResolutionDartType>[],
Map<String, ResolutionDartType> namedParameters}) {
List<String> namedParameterNames = <String>[];
List<ResolutionDartType> namedParameterTypes = <ResolutionDartType>[];
if (namedParameters != null) {
namedParameters.forEach((String name, ResolutionDartType type) {
namedParameterNames.add(name);
namedParameterTypes.add(type);
});
}
return new ResolutionFunctionType.synthesized(returnType, parameters,
optionalParameters, namedParameterNames, namedParameterTypes);
}
ClosedWorld get closedWorld {
if (testBackendWorld) {
return compiler.backendClosedWorldForTesting;
} else {
return compiler.resolutionWorldBuilder.closedWorldForTesting;
}
}
}