diff --git a/pkg/dev_compiler/bin/edit_files.dart b/pkg/dev_compiler/bin/edit_files.dart index c7344df95e0..e81c254ee1c 100644 --- a/pkg/dev_compiler/bin/edit_files.dart +++ b/pkg/dev_compiler/bin/edit_files.dart @@ -23,7 +23,6 @@ import 'package:source_span/source_span.dart'; import 'package:dev_compiler/src/analysis_context.dart'; import 'package:dev_compiler/src/options.dart'; import 'package:dev_compiler/src/summary.dart'; -import 'package:dev_compiler/strong_mode.dart'; final ArgParser argParser = new ArgParser() ..addOption('level', help: 'Minimum error level', defaultsTo: "info") @@ -154,8 +153,7 @@ void main(List argv) { ? new RegExp(args['include-pattern']) : null; - var context = - createAnalysisContextWithSources(new StrongModeOptions(), options); + var context = createAnalysisContextWithSources(options); var visitor = new EditFileSummaryVisitor( context, args['level'], diff --git a/pkg/dev_compiler/lib/devc.dart b/pkg/dev_compiler/lib/devc.dart index bc29b465967..56fc6517a96 100644 --- a/pkg/dev_compiler/lib/devc.dart +++ b/pkg/dev_compiler/lib/devc.dart @@ -9,7 +9,6 @@ export 'src/analysis_context.dart' show createAnalysisContext, createAnalysisContextWithSources; export 'src/compiler.dart' show BatchCompiler, setupLogger, createErrorReporter; export 'src/server/server.dart' show DevServer; -export 'strong_mode.dart' show StrongModeOptions; // When updating this version, also update the version in the pubspec. const devCompilerVersion = '0.1.9'; diff --git a/pkg/dev_compiler/lib/src/analysis_context.dart b/pkg/dev_compiler/lib/src/analysis_context.dart index b2d445129e7..79ec11216f7 100644 --- a/pkg/dev_compiler/lib/src/analysis_context.dart +++ b/pkg/dev_compiler/lib/src/analysis_context.dart @@ -10,9 +10,6 @@ import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk; import 'package:analyzer/src/generated/source.dart' show DartUriResolver; import 'package:analyzer/src/generated/source_io.dart'; -import '../strong_mode.dart' show StrongModeOptions; - -import 'checker/resolver.dart'; import 'dart_sdk.dart'; import 'multi_package_resolver.dart'; import 'options.dart'; @@ -20,29 +17,22 @@ import 'options.dart'; /// Creates an [AnalysisContext] with dev_compiler type rules and inference, /// using [createSourceFactory] to set up its [SourceFactory]. AnalysisContext createAnalysisContextWithSources( - StrongModeOptions strongOptions, SourceResolverOptions srcOptions, - {DartUriResolver sdkResolver, List fileResolvers}) { + SourceResolverOptions srcOptions, + {DartUriResolver sdkResolver, + List fileResolvers}) { AnalysisEngine.instance.useTaskModel = true; var srcFactory = createSourceFactory(srcOptions, sdkResolver: sdkResolver, fileResolvers: fileResolvers); - return createAnalysisContext(strongOptions)..sourceFactory = srcFactory; + return createAnalysisContext()..sourceFactory = srcFactory; } /// Creates an analysis context that contains our restricted typing rules. -AnalysisContext createAnalysisContext(StrongModeOptions options) { +AnalysisContext createAnalysisContext() { var res = AnalysisEngine.instance.createAnalysisContext(); res.analysisOptions.strongMode = true; return res; } -/// Enables dev_compiler inference rules. -// TODO(jmesserly): is there a cleaner way to plug this in? -void enableDevCompilerInference( - AnalysisContextImpl context, StrongModeOptions options) { - context.libraryResolverFactory = (c) => - new LibraryResolverWithInference(c, options); -} - /// Creates a SourceFactory configured by the [options]. /// /// Use [options.useMockSdk] to specify the SDK mode, or use [sdkResolver] diff --git a/pkg/dev_compiler/lib/src/checker/checker.dart b/pkg/dev_compiler/lib/src/checker/checker.dart deleted file mode 100644 index 10bae9cfb39..00000000000 --- a/pkg/dev_compiler/lib/src/checker/checker.dart +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2015, 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 dev_compiler.src.checker.checker; - -export 'package:analyzer/src/task/strong/checker.dart'; diff --git a/pkg/dev_compiler/lib/src/checker/resolver.dart b/pkg/dev_compiler/lib/src/checker/resolver.dart deleted file mode 100644 index 1e141cf0157..00000000000 --- a/pkg/dev_compiler/lib/src/checker/resolver.dart +++ /dev/null @@ -1,757 +0,0 @@ -// Copyright (c) 2015, 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. - -/// Encapsulates how to invoke the analyzer resolver and overrides how it -/// computes types on expressions to use our restricted set of types. -library dev_compiler.src.checker.resolver; - -import 'package:analyzer/analyzer.dart'; -import 'package:analyzer/src/generated/ast.dart'; -import 'package:analyzer/src/generated/element.dart'; -import 'package:analyzer/src/generated/resolver.dart'; -import 'package:analyzer/src/generated/source.dart' show Source; -import 'package:analyzer/src/generated/source_io.dart'; -import 'package:analyzer/src/generated/static_type_analyzer.dart'; -import 'package:analyzer/src/generated/utilities_collection.dart' - show DirectedGraph; -import 'package:logging/logging.dart' as logger; - -import '../../strong_mode.dart' show StrongModeOptions; -import '../utils.dart'; -import 'rules.dart'; - -final _log = new logger.Logger('dev_compiler.src.resolver'); - -/// A [LibraryResolver] that performs inference on top-levels and fields based -/// on the value of the initializer, and on fields and methods based on -/// overridden members in super classes. -class LibraryResolverWithInference extends LibraryResolver { - final StrongModeOptions _options; - - LibraryResolverWithInference(context, this._options) : super(context); - - @override - void resolveReferencesAndTypes() { - _resolveVariableReferences(); - - // Run resolution in two stages, skipping method bodies first, so we can run - // type-inference before we fully analyze methods. - var visitors = _createVisitors(); - _resolveEverything(visitors); - _runInference(visitors); - - visitors.values.forEach((v) => v.skipMethodBodies = false); - _resolveEverything(visitors); - } - - // Note: this was split from _resolveReferencesAndTypesInLibrary so we do it - // only once. - void _resolveVariableReferences() { - for (Library library in resolvedLibraries) { - for (Source source in library.compilationUnitSources) { - library.getAST(source).accept(new VariableResolverVisitor( - library.libraryElement, source, typeProvider, library.errorListener, - nameScope: library.libraryScope)); - } - } - } - - // Note: this was split from _resolveReferencesAndTypesInLibrary so we can do - // resolution in pieces. - Map _createVisitors() { - var visitors = {}; - for (Library library in resolvedLibraries) { - for (Source source in library.compilationUnitSources) { - var visitor = new RestrictedResolverVisitor( - library, source, typeProvider, _options); - visitors[source] = visitor; - } - } - return visitors; - } - - /// Runs the resolver on the entire library cycle. - void _resolveEverything(Map visitors) { - for (Library library in resolvedLibraries) { - for (Source source in library.compilationUnitSources) { - library.getAST(source).accept(visitors[source]); - } - } - } - - _runInference(Map visitors) { - var globalsAndStatics = []; - var classes = []; - - // Extract top-level members that are const, statics, or classes. - for (Library library in resolvedLibraries) { - for (Source source in library.compilationUnitSources) { - CompilationUnit ast = library.getAST(source); - for (var declaration in ast.declarations) { - if (declaration is TopLevelVariableDeclaration) { - globalsAndStatics.addAll(declaration.variables.variables); - } else if (declaration is ClassDeclaration) { - classes.add(declaration); - for (var member in declaration.members) { - if (member is FieldDeclaration && - (member.fields.isConst || member.isStatic)) { - globalsAndStatics.addAll(member.fields.variables); - } - } - } - } - } - } - _inferGlobalsAndStatics(globalsAndStatics, visitors); - _inferInstanceFields(classes, visitors); - } - - _inferGlobalsAndStatics(List globalsAndStatics, - Map visitors) { - var elementToDeclaration = {}; - for (var c in globalsAndStatics) { - elementToDeclaration[c.element] = c; - } - var constGraph = new DirectedGraph(); - globalsAndStatics.forEach(constGraph.addNode); - for (var c in globalsAndStatics) { - for (var e in _VarExtractor.extract(c.initializer)) { - // Note: declaration is null for variables that come from other strongly - // connected components. - var declaration = elementToDeclaration[e]; - if (declaration != null) constGraph.addEdge(c, declaration); - } - } - - for (var component in constGraph.computeTopologicalSort()) { - component.forEach((v) => _reanalyzeVar(visitors, v)); - _inferVariableFromInitializer(component); - } - } - - _inferInstanceFields(List classes, - Map visitors) { - // First propagate what was inferred from globals to all instance fields. - - // TODO(sigmund): also do a fine-grain propagation between fields. We want - // infer-by-override to take precedence, so we would have to include - // classes in the dependency graph and ensure that fields depend on their - // class, and classes depend on superclasses. - classes - .expand((c) => c.members.where(_isInstanceField)) - .expand((f) => f.fields.variables) - .forEach((v) => _reanalyzeVar(visitors, v)); - - // Track types in this strongly connected component, ensure we visit - // supertypes before subtypes. - var typeToDeclaration = {}; - classes.forEach((c) => typeToDeclaration[c.element.type] = c); - var seen = new Set(); - visit(ClassDeclaration cls) { - var element = cls.element; - var type = element.type; - if (seen.contains(type)) return; - seen.add(type); - for (var supertype in element.allSupertypes) { - var supertypeClass = typeToDeclaration[supertype]; - if (supertypeClass != null) visit(supertypeClass); - } - - // Infer field types from overrides first, otherwise from initializers. - var pending = new Set(); - cls.members - .where(_isInstanceField) - .forEach((f) => _inferFieldTypeFromOverride(f, pending)); - if (pending.isNotEmpty) _inferVariableFromInitializer(pending); - - // Infer return-types and param-types from overrides - cls.members - .where((m) => m is MethodDeclaration && !m.isStatic) - .forEach(_inferMethodTypesFromOverride); - } - classes.forEach(visit); - } - - void _reanalyzeVar(Map visitors, - VariableDeclaration variable) { - if (variable.initializer == null) return; - var visitor = visitors[(variable.root as CompilationUnit).element.source]; - visitor.reanalyzeInitializer(variable); - } - - static bool _isInstanceField(f) => - f is FieldDeclaration && !f.isStatic && !f.fields.isConst; - - /// Attempts to infer the type on [field] from overridden fields or getters if - /// a type was not specified. If no type could be inferred, but it contains an - /// initializer, we add it to [pending] so we can try to infer it using the - /// initializer type instead. - void _inferFieldTypeFromOverride( - FieldDeclaration field, Set pending) { - var variables = field.fields; - for (var variable in variables.variables) { - var varElement = variable.element as FieldElement; - if (!varElement.type.isDynamic || variables.type != null) continue; - var getter = varElement.getter; - // Note: type will be null only when there are no overrides. When some - // override's type was not specified and couldn't be inferred, the type - // here will be dynamic. - var enclosingElement = varElement.enclosingElement; - var type = searchTypeFor(enclosingElement.type, getter); - - // Infer from the RHS when there are no overrides. - if (type == null) { - if (variable.initializer != null) pending.add(variable); - continue; - } - - // When field is final and overridden getter is dynamic, we can infer from - // the RHS without breaking subtyping rules (return type is covariant). - if (type.returnType.isDynamic) { - if (variables.isFinal && variable.initializer != null) { - pending.add(variable); - } - continue; - } - - // Use type from the override. - var newType = type.returnType; - varElement.type = newType; - varElement.getter.returnType = newType; - if (!varElement.isFinal) varElement.setter.parameters[0].type = newType; - } - } - - void _inferMethodTypesFromOverride(MethodDeclaration method) { - var methodElement = method.element; - if (methodElement is! MethodElement && - methodElement is! PropertyAccessorElement) return; - - var enclosingElement = methodElement.enclosingElement as ClassElement; - FunctionType type = null; - - // Infer the return type if omitted - if (methodElement.returnType.isDynamic && method.returnType == null) { - type = searchTypeFor(enclosingElement.type, methodElement); - if (type == null) return; - if (!type.returnType.isDynamic) { - methodElement.returnType = type.returnType; - } - } - - // Infer parameter types if omitted - if (method.parameters == null) return; - var parameters = method.parameters.parameters; - var length = parameters.length; - for (int i = 0; i < length; ++i) { - var parameter = parameters[i]; - if (parameter is DefaultFormalParameter) parameter = parameter.parameter; - if (parameter is SimpleFormalParameter && parameter.type == null) { - type = type ?? searchTypeFor(enclosingElement.type, methodElement); - if (type == null) return; - if (type.parameters.length > i && !type.parameters[i].type.isDynamic) { - parameter.element.type = type.parameters[i].type; - } - } - } - } - - void _inferVariableFromInitializer(Iterable variables) { - for (var variable in variables) { - var declaration = variable.parent as VariableDeclarationList; - // Only infer on variables that don't have any declared type. - if (declaration.type != null) continue; - var initializer = variable.initializer; - if (initializer == null) continue; - var type = initializer.staticType; - if (type == null || type.isDynamic || type.isBottom) continue; - var element = variable.element as PropertyInducingElement; - // Note: it's ok to update the type here, since initializer.staticType - // is already computed for all declarations in the library cycle. The - // new types will only be propagated on a second run of the - // ResolverVisitor. - element.type = type; - element.getter.returnType = type; - if (!element.isFinal && !element.isConst) { - element.setter.parameters[0].type = type; - } - } - } -} - -/// Extracts the [VariableElement]s used in an initializer expression. -class _VarExtractor extends RecursiveAstVisitor { - final elements = []; - visitSimpleIdentifier(SimpleIdentifier node) { - var e = node.staticElement; - if (e is PropertyAccessorElement) elements.add(e.variable); - } - - static List extract(Expression initializer) { - if (initializer == null) return const []; - var extractor = new _VarExtractor(); - initializer.accept(extractor); - return extractor.elements; - } -} - -/// Overrides the default [ResolverVisitor] to support type inference in -/// [LibraryResolverWithInference] above. -/// -/// Before inference, this visitor is used to resolve top-levels, classes, and -/// fields, but nothing within method bodies. After inference, this visitor is -/// used again to step into method bodies and complete resolution as a second -/// phase. -class RestrictedResolverVisitor extends ResolverVisitor { - final TypeProvider _typeProvider; - - /// Whether to skip resolution within method bodies. - bool skipMethodBodies = true; - - /// State of the resolver at the point a field or variable was declared. - final _stateAtDeclaration = {}; - - /// Internal tracking of whether a node was skipped while visiting, for - /// example, if it contained a function expression with a function body. - bool _nodeWasSkipped = false; - - /// Internal state, whether we are revisiting an initializer, so we minimize - /// the work being done elsewhere. - bool _revisiting = false; - - /// Initializers that have been visited, reanalyzed, and for which no node was - /// internally skipped. These initializers are fully resolved and don't need - /// to be re-resolved on a sunsequent pass. - final _visitedInitializers = new Set(); - - RestrictedResolverVisitor(Library library, Source source, - TypeProvider typeProvider, StrongModeOptions options) - : _typeProvider = typeProvider, - super( - library.libraryElement, source, typeProvider, library.errorListener, - nameScope: library.libraryScope, - inheritanceManager: library.inheritanceManager, - typeAnalyzerFactory: RestrictedStaticTypeAnalyzer.constructor); - - reanalyzeInitializer(VariableDeclaration variable) { - try { - _revisiting = true; - _nodeWasSkipped = false; - var node = variable.parent.parent; - var oldState; - var state = _stateAtDeclaration[node]; - if (state != null) { - oldState = new _ResolverState(this); - state.restore(this); - if (node is FieldDeclaration) { - var cls = node.parent as ClassDeclaration; - enclosingClass = cls.element; - } - } - visitNode(variable.initializer); - if (!_nodeWasSkipped) _visitedInitializers.add(variable); - if (oldState != null) oldState.restore(this); - } finally { - _revisiting = false; - } - } - - @override - Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { - _stateAtDeclaration[node] = new _ResolverState(this); - return super.visitTopLevelVariableDeclaration(node); - } - - @override - Object visitFieldDeclaration(FieldDeclaration node) { - _stateAtDeclaration[node] = new _ResolverState(this); - return super.visitFieldDeclaration(node); - } - - Object visitVariableDeclaration(VariableDeclaration node) { - var state = new _ResolverState(this); - try { - if (_revisiting) { - _stateAtDeclaration[node].restore(this); - } else { - _stateAtDeclaration[node] = state; - } - return super.visitVariableDeclaration(node); - } finally { - state.restore(this); - } - } - - @override - Object visitNode(AstNode node) { - if (skipMethodBodies && node is FunctionBody) { - _nodeWasSkipped = true; - return null; - } - if (_visitedInitializers.contains(node)) return null; - assert(node is! Statement || !skipMethodBodies); - return super.visitNode(node); - } - - @override - Object visitMethodDeclaration(MethodDeclaration node) { - if (skipMethodBodies) { - node.accept(elementResolver); - node.accept(typeAnalyzer); - return null; - } else { - return super.visitMethodDeclaration(node); - } - } - - @override - Object visitFunctionDeclaration(FunctionDeclaration node) { - if (skipMethodBodies) { - node.accept(elementResolver); - node.accept(typeAnalyzer); - return null; - } else { - return super.visitFunctionDeclaration(node); - } - } - - @override - Object visitConstructorDeclaration(ConstructorDeclaration node) { - if (skipMethodBodies) { - node.accept(elementResolver); - node.accept(typeAnalyzer); - return null; - } else { - return super.visitConstructorDeclaration(node); - } - } - - @override - visitFieldFormalParameter(FieldFormalParameter node) { - // Ensure the field formal parameter's type is updated after inference. - // Normally this happens during TypeResolver, but that's before we've done - // inference on the field type. - var element = node.element; - if (element is FieldFormalParameterElement) { - if (element.type.isDynamic) { - // In malformed code, there may be no actual field. - if (element.field != null) { - element.type = element.field.type; - } - } - } - super.visitFieldFormalParameter(node); - } -} - -/// Internal state of the resolver, stored so we can reanalyze portions of the -/// AST quickly, without recomputing everything from the top. -class _ResolverState { - final TypePromotionManager_TypePromoteScope promotionScope; - final TypeOverrideManager_TypeOverrideScope overrideScope; - final Scope nameScope; - - _ResolverState(ResolverVisitor visitor) - : promotionScope = visitor.promoteManager.currentScope, - overrideScope = visitor.overrideManager.currentScope, - nameScope = visitor.nameScope; - - void restore(ResolverVisitor visitor) { - visitor.promoteManager.currentScope = promotionScope; - visitor.overrideManager.currentScope = overrideScope; - visitor.nameScope = nameScope; - } -} - -/// Overrides the default [StaticTypeAnalyzer] to adjust rules that are stricter -/// in the restricted type system and to infer types for untyped local -/// variables. -class RestrictedStaticTypeAnalyzer extends StaticTypeAnalyzer { - final TypeProvider _typeProvider; - Map _objectMembers; - - RestrictedStaticTypeAnalyzer(ResolverVisitor r) - : _typeProvider = r.typeProvider, - super(r) { - _objectMembers = getObjectMemberMap(_typeProvider); - } - - static constructor(ResolverVisitor r) => new RestrictedStaticTypeAnalyzer(r); - - @override // to infer type from initializers - visitVariableDeclaration(VariableDeclaration node) { - _inferType(node); - return super.visitVariableDeclaration(node); - } - - /// Infer the type of a variable based on the initializer's type. - void _inferType(VariableDeclaration node) { - var initializer = node.initializer; - if (initializer == null) return; - - var declaredType = (node.parent as VariableDeclarationList).type; - if (declaredType != null) return; - var element = node.element; - if (element is! LocalVariableElement) return; - if (element.type != _typeProvider.dynamicType) return; - - var type = initializer.staticType; - if (type == null || type == _typeProvider.bottomType) return; - element.type = type; - if (element is PropertyInducingElement) { - element.getter.returnType = type; - if (!element.isFinal && !element.isConst) { - element.setter.parameters[0].type = type; - } - } - } - - // TODO(vsm): Use leafp's matchType here? - DartType _findIteratedType(InterfaceType type) { - if (type.element == _typeProvider.iterableType.element) { - var typeArguments = type.typeArguments; - assert(typeArguments.length == 1); - return typeArguments[0]; - } - - if (type == _typeProvider.objectType) return null; - - var result = _findIteratedType(type.superclass); - if (result != null) return result; - - for (final parent in type.interfaces) { - result = _findIteratedType(parent); - if (result != null) return result; - } - - for (final parent in type.mixins) { - result = _findIteratedType(parent); - if (result != null) return result; - } - - return null; - } - - @override - visitDeclaredIdentifier(DeclaredIdentifier node) { - super.visitDeclaredIdentifier(node); - if (node.type != null) return; - - var parent = node.parent as ForEachStatement; - var expr = parent.iterable; - var element = node.element as LocalVariableElementImpl; - var exprType = expr.staticType; - if (exprType is InterfaceType) { - var iteratedType = _findIteratedType(exprType); - if (iteratedType != null) { - element.type = iteratedType; - } - } - } - - bool _isSealed(DartType t) { - return _typeProvider.nonSubtypableTypes.contains(t); - } - - List _genericList = null; - - DartType _matchGeneric(MethodInvocation node, Element element) { - var e = node.methodName.staticElement; - - if (_genericList == null) { - var minmax = (DartType tx, DartType ty) => (tx == ty && - (tx == _typeProvider.intType || tx == _typeProvider.doubleType)) - ? tx - : null; - - var map = (DartType tx) => (tx is FunctionType) - ? _typeProvider.iterableType.substitute4([tx.returnType]) - : null; - - // TODO(vsm): LUB? - var fold = (DartType tx, DartType ty) => - (ty is FunctionType && tx == ty.returnType) ? tx : null; - - // TODO(vsm): Flatten? - var then = (DartType tx) => (tx is FunctionType) - ? _typeProvider.futureType.substitute4([tx.returnType]) - : null; - - var wait = (DartType tx) { - // Iterable> -> Future> - var futureType = _findIteratedType(tx); - if (futureType.element.type != _typeProvider.futureType) return null; - var typeArguments = futureType.typeArguments; - if (typeArguments.length != 1) return null; - var baseType = typeArguments[0]; - if (baseType.isDynamic) return null; - return _typeProvider.futureType.substitute4([ - _typeProvider.listType.substitute4([baseType]) - ]); - }; - - _genericList = [ - // Top-level methods - ['dart:math', 'max', 2, minmax], - ['dart:math', 'min', 2, minmax], - // Static methods - [_typeProvider.futureType, 'wait', 1, wait], - // Instance methods - [_typeProvider.iterableDynamicType, 'map', 1, map], - [_typeProvider.iterableDynamicType, 'fold', 2, fold], - [_typeProvider.futureDynamicType, 'then', 1, then], - ]; - } - - var targetType = node.target?.staticType; - var arguments = node.argumentList.arguments; - - for (var generic in _genericList) { - if (e?.name == generic[1]) { - if ((generic[0] is String && - element?.library.source.uri.toString() == generic[0]) || - (generic[0] is DartType && - targetType != null && - targetType.isSubtypeOf(generic[0]))) { - if (arguments.length == generic[2]) { - return Function.apply( - generic[3], arguments.map((arg) => arg.staticType).toList()); - } - } - } - } - - return null; - } - - @override // to propagate types to identifiers - visitMethodInvocation(MethodInvocation node) { - // TODO(jmesserly): we rely on having a staticType propagated to the - // methodName identifier. This shouldn't be necessary for method calls, so - // analyzer doesn't do it by default. Conceptually what we're doing here - // is asking for a tear off. We need this until we can fix #132, and rely - // on `node.staticElement == null` instead of `rules.isDynamicCall(node)`. - visitSimpleIdentifier(node.methodName); - - super.visitMethodInvocation(node); - - // Search for Object methods. - var name = node.methodName.name; - if (node.staticType.isDynamic && - _objectMembers.containsKey(name) && - isDynamicTarget(node.target)) { - var type = _objectMembers[name]; - if (type is FunctionType && - type.parameters.isEmpty && - node.argumentList.arguments.isEmpty) { - node.methodName.staticType = type; - // Only infer the type of the overall expression if we have an exact - // type - e.g., a sealed type. Otherwise, it may be too strict. - if (_isSealed(type.returnType)) { - node.staticType = type.returnType; - } - } - } - - var e = node.methodName.staticElement; - if (isInlineJS(e)) { - // Fix types for JS builtin calls. - // - // This code was taken from analyzer. It's not super sophisticated: - // only looks for the type name in dart:core, so we just copy it here. - // - // TODO(jmesserly): we'll likely need something that can handle a wider - // variety of types, especially when we get to JS interop. - var args = node.argumentList.arguments; - var first = args.isNotEmpty ? args.first : null; - if (first is SimpleStringLiteral) { - var typeStr = first.stringValue; - if (typeStr == '-dynamic') { - node.staticType = _typeProvider.bottomType; - } else { - var coreLib = _typeProvider.objectType.element.library; - var classElem = coreLib.getType(typeStr); - if (classElem != null) { - var type = fillDynamicTypeArgs(classElem.type, _typeProvider); - node.staticType = type; - } - } - } - } - - // Pretend dart:math's min and max are generic: - // - // T min(T x, T y); - // - // and infer T. In practice, this just means if the type of x and y are - // both double or both int, we treat that as the return type. - // - // The Dart spec has similar treatment for binary operations on numbers. - // - // TODO(jmesserly): remove this when we have a fix for - // https://github.com/dart-lang/dev_compiler/issues/28 - var inferred = _matchGeneric(node, e); - // TODO(vsm): If the inferred type is not a subtype, should we use a GLB instead? - if (inferred != null && inferred.isSubtypeOf(node.staticType)) { - node.staticType = inferred; - } - } - - void _inferObjectAccess( - Expression node, Expression target, SimpleIdentifier id) { - // Search for Object accesses. - var name = id.name; - if (node.staticType.isDynamic && - _objectMembers.containsKey(name) && - isDynamicTarget(target)) { - var type = _objectMembers[name]; - id.staticType = type; - // Only infer the type of the overall expression if we have an exact - // type - e.g., a sealed type. Otherwise, it may be too strict. - if (_isSealed(type)) { - node.staticType = type; - } - } - } - - @override - visitPropertyAccess(PropertyAccess node) { - super.visitPropertyAccess(node); - - _inferObjectAccess(node, node.target, node.propertyName); - } - - @override - visitPrefixedIdentifier(PrefixedIdentifier node) { - super.visitPrefixedIdentifier(node); - - _inferObjectAccess(node, node.prefix, node.identifier); - } - - @override - visitConditionalExpression(ConditionalExpression node) { - // TODO(vsm): The static type of a conditional should be the LUB of the - // then and else expressions. The analyzer appears to compute dynamic when - // one or the other is the null literal. Remove this fix once the - // corresponding analyzer bug is fixed: - // https://code.google.com/p/dart/issues/detail?id=22854 - super.visitConditionalExpression(node); - if (node.staticType.isDynamic) { - var thenExpr = node.thenExpression; - var elseExpr = node.elseExpression; - if (thenExpr.staticType.isBottom) { - node.staticType = elseExpr.staticType; - } else if (elseExpr.staticType.isBottom) { - node.staticType = thenExpr.staticType; - } - } - } - - // Review note: no longer need to override visitFunctionExpression, this is - // handled by the analyzer internally. - // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? - // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression - // type in a (...) => expr or just the written type? - -} diff --git a/pkg/dev_compiler/lib/src/checker/rules.dart b/pkg/dev_compiler/lib/src/checker/rules.dart deleted file mode 100644 index eebfcac6da4..00000000000 --- a/pkg/dev_compiler/lib/src/checker/rules.dart +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2015, 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 dev_compiler.src.checker.rules; - -export 'package:analyzer/src/task/strong/rules.dart'; diff --git a/pkg/dev_compiler/lib/src/codegen/code_generator.dart b/pkg/dev_compiler/lib/src/codegen/code_generator.dart index 12cc751a19f..5a654e246a9 100644 --- a/pkg/dev_compiler/lib/src/codegen/code_generator.dart +++ b/pkg/dev_compiler/lib/src/codegen/code_generator.dart @@ -7,12 +7,12 @@ library dev_compiler.src.codegen.code_generator; import 'package:analyzer/src/generated/element.dart' show CompilationUnitElement, LibraryElement; import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; +import 'package:analyzer/src/task/strong/rules.dart'; import 'package:path/path.dart' as path; import '../compiler.dart' show AbstractCompiler; import '../info.dart'; import '../utils.dart' show canonicalLibraryName; -import '../checker/rules.dart'; import '../options.dart' show CodegenOptions; abstract class CodeGenerator { diff --git a/pkg/dev_compiler/lib/src/codegen/js_codegen.dart b/pkg/dev_compiler/lib/src/codegen/js_codegen.dart index daea2b29cf0..efcbfdf2c4c 100644 --- a/pkg/dev_compiler/lib/src/codegen/js_codegen.dart +++ b/pkg/dev_compiler/lib/src/codegen/js_codegen.dart @@ -14,6 +14,7 @@ import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; import 'package:analyzer/src/generated/scanner.dart' show StringToken, Token, TokenType; import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; +import 'package:analyzer/src/task/strong/rules.dart'; import 'ast_builder.dart' show AstBuilder; import 'reify_coercions.dart' show CoercionReifier, Tuple2; @@ -24,7 +25,6 @@ import '../js/js_ast.dart' show js; import '../closure/closure_annotator.dart' show ClosureAnnotator; import '../compiler.dart' show AbstractCompiler; -import '../checker/rules.dart'; import '../info.dart'; import '../options.dart' show CodegenOptions; import '../utils.dart'; diff --git a/pkg/dev_compiler/lib/src/codegen/reify_coercions.dart b/pkg/dev_compiler/lib/src/codegen/reify_coercions.dart index 3bf1d911129..7e91a9cefe8 100644 --- a/pkg/dev_compiler/lib/src/codegen/reify_coercions.dart +++ b/pkg/dev_compiler/lib/src/codegen/reify_coercions.dart @@ -7,9 +7,9 @@ library dev_compiler.src.codegen.reify_coercions; import 'package:analyzer/analyzer.dart' as analyzer; import 'package:analyzer/src/generated/ast.dart'; import 'package:analyzer/src/generated/element.dart'; +import 'package:analyzer/src/task/strong/rules.dart'; import 'package:logging/logging.dart' as logger; -import '../checker/rules.dart'; import '../info.dart'; import 'ast_builder.dart'; diff --git a/pkg/dev_compiler/lib/src/compiler.dart b/pkg/dev_compiler/lib/src/compiler.dart index 761ce26082e..9d6f04b5b49 100644 --- a/pkg/dev_compiler/lib/src/compiler.dart +++ b/pkg/dev_compiler/lib/src/compiler.dart @@ -63,8 +63,7 @@ CompilerOptions validateOptions(List args, {bool forceOutDir: false}) { bool compile(CompilerOptions options) { assert(!options.serverMode); - var context = createAnalysisContextWithSources( - options.strongOptions, options.sourceOptions); + var context = createAnalysisContextWithSources(options.sourceOptions); var reporter = createErrorReporter(context, options); bool status = new BatchCompiler(context, options, reporter: reporter).run(); diff --git a/pkg/dev_compiler/lib/src/options.dart b/pkg/dev_compiler/lib/src/options.dart index 7978c1091b3..62c916aa5a0 100644 --- a/pkg/dev_compiler/lib/src/options.dart +++ b/pkg/dev_compiler/lib/src/options.dart @@ -13,8 +13,6 @@ import 'package:logging/logging.dart' show Level; import 'package:path/path.dart' as path; import 'package:yaml/yaml.dart'; -import '../strong_mode.dart' show StrongModeOptions; - const bool _CLOSURE_DEFAULT = false; /// Options used to set up Source URI resolution in the analysis context. @@ -94,7 +92,6 @@ class RunnerOptions { /// General options used by the dev compiler and server. class CompilerOptions { - final StrongModeOptions strongOptions; final SourceResolverOptions sourceOptions; final CodegenOptions codegenOptions; final RunnerOptions runnerOptions; @@ -149,8 +146,7 @@ class CompilerOptions { final String inputBaseDir; CompilerOptions( - {this.strongOptions: const StrongModeOptions(), - this.sourceOptions: const SourceResolverOptions(), + {this.sourceOptions: const SourceResolverOptions(), this.codegenOptions: const CodegenOptions(), this.runnerOptions: const RunnerOptions(), this.checkSdk: false, @@ -238,7 +234,6 @@ CompilerOptions parseOptions(List argv, {bool forceOutDir: false}) { packagePaths: args['package-paths'].split(','), resources: args['resources'].split(',').where((s) => s.isNotEmpty).toList()), - strongOptions: new StrongModeOptions.fromArguments(args), runnerOptions: new RunnerOptions(v8Binary: v8Binary), checkSdk: args['sdk-check'], dumpInfo: dumpInfo, @@ -256,7 +251,7 @@ CompilerOptions parseOptions(List argv, {bool forceOutDir: false}) { inputs: args.rest); } -final ArgParser argParser = StrongModeOptions.addArguments(new ArgParser() +final ArgParser argParser = new ArgParser() ..addFlag('sdk-check', abbr: 's', help: 'Typecheck sdk libs', defaultsTo: false) ..addFlag('mock-sdk', @@ -321,7 +316,7 @@ final ArgParser argParser = StrongModeOptions.addArguments(new ArgParser() ..addOption('dump-info-file', abbr: 'f', help: 'Dump info json file (requires dump-info)', - defaultsTo: null)); + defaultsTo: null); // TODO: Switch over to the `pub_cache` package (or the Resource API)? diff --git a/pkg/dev_compiler/lib/src/server/server.dart b/pkg/dev_compiler/lib/src/server/server.dart index 079b2311d43..8bb0518e13e 100644 --- a/pkg/dev_compiler/lib/src/server/server.dart +++ b/pkg/dev_compiler/lib/src/server/server.dart @@ -210,8 +210,7 @@ class DevServer { fileResolvers.insert(0, _createImplicitEntryResolver(options.inputs[0])); } - var context = createAnalysisContextWithSources( - options.strongOptions, options.sourceOptions, + var context = createAnalysisContextWithSources(options.sourceOptions, fileResolvers: fileResolvers); var entryPath = path.basename(options.inputs[0]); diff --git a/pkg/dev_compiler/lib/strong_mode.dart b/pkg/dev_compiler/lib/strong_mode.dart deleted file mode 100644 index 45d17ab50ff..00000000000 --- a/pkg/dev_compiler/lib/strong_mode.dart +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2015, 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. - -/// Types needed to implement "strong" checking in the Dart analyzer. This is -/// intended to be used by `analyzer_cli` and `analysis_server` packages. -library dev_compiler.strong_mode; - -import 'package:analyzer/src/generated/engine.dart' - show - AnalysisContext, - AnalysisContextImpl, - AnalysisEngine, - AnalysisErrorInfo, - AnalysisErrorInfoImpl; -import 'package:analyzer/src/generated/error.dart' - show - AnalysisError, - AnalysisErrorListener, - CompileTimeErrorCode, - ErrorCode, - ErrorSeverity, - HintCode, - StaticTypeWarningCode; -import 'package:analyzer/src/generated/source.dart' show Source; -import 'package:args/args.dart'; - -import 'src/analysis_context.dart' show enableDevCompilerInference; -import 'src/checker/checker.dart' show CodeChecker; -import 'src/checker/rules.dart' show TypeRules; - -/// A type checker for Dart code that operates under stronger rules, and has -/// the ability to do local type inference in some situations. -// TODO(jmesserly): remove this class. -class StrongChecker { - final AnalysisContext _context; - final CodeChecker _checker; - final _ErrorCollector _reporter; - - StrongChecker._(this._context, this._checker, this._reporter); - - factory StrongChecker(AnalysisContext context, StrongModeOptions options) { - // TODO(vsm): Remove this once analyzer_cli is completely switched to the - // task model. - if (!AnalysisEngine.instance.useTaskModel) { - enableDevCompilerInference(context, options); - var rules = new TypeRules(context.typeProvider); - var reporter = new _ErrorCollector(options.hints); - var checker = new CodeChecker(rules, reporter); - return new StrongChecker._(context, checker, reporter); - } - return new StrongChecker._(context, null, null); - } - - /// Computes and returns DDC errors for the [source]. - AnalysisErrorInfo computeErrors(Source source) { - var errors = new List(); - if (_checker != null) { - _reporter.errors = errors; - - for (Source librarySource in _context.getLibrariesContaining(source)) { - var resolved = _context.resolveCompilationUnit2(source, librarySource); - _checker.visitCompilationUnit(resolved); - } - _reporter.errors = null; - } - return new AnalysisErrorInfoImpl(errors, _context.getLineInfo(source)); - } -} - -class _ErrorCollector implements AnalysisErrorListener { - List errors; - final bool hints; - _ErrorCollector(this.hints); - - void onError(AnalysisError error) { - // Unless DDC hints are requested, filter them out. - var HINT = ErrorSeverity.INFO.ordinal; - if (hints || error.errorCode.errorSeverity.ordinal > HINT) { - errors.add(error); - } - } -} - -// TODO(jmesserly): this type is dead now. It's preserved because analyzer_cli -// passes the `hints` option. -class StrongModeOptions { - /// Whether to include hints about dynamic invokes and runtime checks. - // TODO(jmesserly): this option is not used yet by DDC server mode or batch - // compile to JS. - final bool hints; - - const StrongModeOptions({this.hints: false}); - - StrongModeOptions.fromArguments(ArgResults args, {String prefix: ''}) - : hints = args[prefix + 'hints']; - - static ArgParser addArguments(ArgParser parser, - {String prefix: '', bool hide: false}) { - return parser - ..addFlag(prefix + 'hints', - help: 'Display hints about dynamic casts and dispatch operations', - defaultsTo: false, - hide: hide); - } - - bool operator ==(Object other) { - if (other is! StrongModeOptions) return false; - StrongModeOptions s = other; - return hints == s.hints; - } -} diff --git a/pkg/dev_compiler/test/all_tests.dart b/pkg/dev_compiler/test/all_tests.dart index b7c60cafa2e..56051ad11b1 100644 --- a/pkg/dev_compiler/test/all_tests.dart +++ b/pkg/dev_compiler/test/all_tests.dart @@ -7,7 +7,6 @@ library dev_compiler.test.all_tests; import 'package:test/test.dart'; -import 'checker/self_host_test.dart' as self_host; import 'closure/closure_annotation_test.dart' as closure_annotation_test; import 'closure/closure_type_test.dart' as closure_type_test; import 'codegen_test.dart' as codegen_test; @@ -20,7 +19,6 @@ void main() { group('report', report_test.main); group('dependency_graph', dependency_graph_test.main); group('codegen', () => codegen_test.main([])); - group('self_host', self_host.main); group('closure', () { closure_annotation_test.main(); closure_type_test.main(); diff --git a/pkg/dev_compiler/test/checker/checker_test.dart b/pkg/dev_compiler/test/checker/checker_test.dart deleted file mode 100644 index ba9885292fd..00000000000 --- a/pkg/dev_compiler/test/checker/checker_test.dart +++ /dev/null @@ -1,2319 +0,0 @@ -// Copyright (c) 2015, 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. - -/// General type checking tests -library dev_compiler.test.checker_test; - -import 'package:test/test.dart'; - -import '../testing.dart'; - -void main() { - testChecker('ternary operator', { - '/main.dart': ''' - abstract class Comparable { - int compareTo(T other); - static int compare(Comparable a, Comparable b) => a.compareTo(b); - } - typedef int Comparator(T a, T b); - - typedef bool _Predicate(T value); - - class SplayTreeMap { - Comparator _comparator; - _Predicate _validKey; - - // Initializing _comparator needs a cast, since K may not always be - // Comparable. - // Initializing _validKey shouldn't need a cast. Currently - // it requires inference to work because of dartbug.com/23381 - SplayTreeMap([int compare(K key1, K key2), - bool isValidKey(potentialKey)]) { - : _comparator = /*warning:DownCastComposite*/(compare == null) ? Comparable.compare : compare, - _validKey = /*info:InferredType should be pass*/(isValidKey != null) ? isValidKey : ((v) => true); - _Predicate _v = /*warning:DownCastComposite*/(isValidKey != null) ? isValidKey : ((v) => true); - _v = /*info:InferredType should be pass*/(isValidKey != null) ? _v : ((v) => true); - } - } - void main() { - Object obj = 42; - dynamic dyn = 42; - int i = 42; - - // Check the boolean conversion of the condition. - print((/*severe:StaticTypeError*/i) ? false : true); - print((/*info:DownCastImplicit*/obj) ? false : true); - print((/*info:DynamicCast*/dyn) ? false : true); - } - ''' - }); - - testChecker('if/for/do/while statements use boolean conversion', { - '/main.dart': ''' - main() { - dynamic d = 42; - Object obj = 42; - int i = 42; - bool b = false; - - if (b) {} - if (/*info:DynamicCast*/dyn) {} - if (/*info:DownCastImplicit*/obj) {} - if (/*severe:StaticTypeError*/i) {} - - while (b) {} - while (/*info:DynamicCast*/dyn) {} - while (/*info:DownCastImplicit*/obj) {} - while (/*severe:StaticTypeError*/i) {} - - do {} while (b); - do {} while (/*info:DynamicCast*/dyn); - do {} while (/*info:DownCastImplicit*/obj); - do {} while (/*severe:StaticTypeError*/i); - - for (;b;) {} - for (;/*info:DynamicCast*/dyn;) {} - for (;/*info:DownCastImplicit*/obj;) {} - for (;/*severe:StaticTypeError*/i;) {} - } - ''' - }); - - testChecker('dynamic invocation', { - '/main.dart': ''' - - class A { - dynamic call(dynamic x) => x; - } - class B extends A { - int call(int x) => x; - double col(double x) => x; - } - void main() { - { - B f = new B(); - int x; - double y; - // The analyzer has what I believe is a bug (dartbug.com/23252) which - // causes the return type of calls to f to be treated as dynamic. - x = /*info:DynamicCast should be pass*/f(3); - x = /*severe:StaticTypeError*/f.col(3.0); - y = /*info:DynamicCast should be severe:StaticTypeError*/f(3); - y = f.col(3.0); - f(/*severe:StaticTypeError*/3.0); - f.col(/*severe:StaticTypeError*/3); - } - { - Function f = new B(); - int x; - double y; - x = /*info:DynamicCast, info:DynamicInvoke*/f(3); - x = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0); - y = /*info:DynamicCast, info:DynamicInvoke*/f(3); - y = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0); - (/*info:DynamicInvoke*/f(3.0)); - (/*info:DynamicInvoke*/f.col(3)); - } - { - A f = new B(); - int x; - double y; - x = /*info:DynamicCast, info:DynamicInvoke*/f(3); - y = /*info:DynamicCast, info:DynamicInvoke*/f(3); - (/*info:DynamicInvoke*/f(3.0)); - } - } - ''' - }); - - testChecker('conversion and dynamic invoke', { - '/helper.dart': ''' - dynamic toString = (int x) => x + 42; - dynamic hashCode = "hello"; - ''', - '/main.dart': ''' - import 'helper.dart' as helper; - - class A { - String x = "hello world"; - - void baz1(y) => x + /*info:DynamicCast*/y; - static baz2(y) => /*info:DynamicInvoke*/y + y; - } - - void foo(String str) { - print(str); - } - - class B { - String toString([int arg]) => arg.toString(); - } - - void bar(a) { - foo(/*info:DynamicCast,info:DynamicInvoke*/a.x); - } - - baz() => new B(); - - typedef DynFun(x); - typedef StrFun(String x); - - var bar1 = bar; - - void main() { - var a = new A(); - bar(a); - (/*info:DynamicInvoke*/bar1(a)); - var b = bar; - (/*info:DynamicInvoke*/b(a)); - var f1 = foo; - f1("hello"); - dynamic f2 = foo; - (/*info:DynamicInvoke*/f2("hello")); - DynFun f3 = foo; - (/*info:DynamicInvoke*/f3("hello")); - (/*info:DynamicInvoke*/f3(42)); - StrFun f4 = foo; - f4("hello"); - a.baz1("hello"); - var b1 = a.baz1; - (/*info:DynamicInvoke*/b1("hello")); - A.baz2("hello"); - var b2 = A.baz2; - (/*info:DynamicInvoke*/b2("hello")); - - dynamic a1 = new B(); - (/*info:DynamicInvoke*/a1.x); - a1.toString(); - (/*info:DynamicInvoke*/a1.toString(42)); - var toStringClosure = a1.toString; - (/*info:DynamicInvoke*/a1.toStringClosure()); - (/*info:DynamicInvoke*/a1.toStringClosure(42)); - (/*info:DynamicInvoke*/a1.toStringClosure("hello")); - a1.hashCode; - - dynamic toString = () => null; - (/*info:DynamicInvoke*/toString()); - - (/*info:DynamicInvoke*/helper.toString()); - var toStringClosure2 = helper.toString; - (/*info:DynamicInvoke*/toStringClosure2()); - int hashCode = /*info:DynamicCast*/helper.hashCode; - - baz().toString(); - baz().hashCode; - } - ''' - }); - - testChecker('Constructors', { - '/main.dart': ''' - const num z = 25; - Object obj = "world"; - - class A { - int x; - String y; - - A(this.x) : this.y = /*severe:StaticTypeError*/42; - - A.c1(p): this.x = /*info:DownCastImplicit*/z, this.y = /*info:DynamicCast*/p; - - A.c2(this.x, this.y); - - A.c3(/*severe:InvalidParameterDeclaration*/num this.x, String this.y); - } - - class B extends A { - B() : super(/*severe:StaticTypeError*/"hello"); - - B.c2(int x, String y) : super.c2(/*severe:StaticTypeError*/y, - /*severe:StaticTypeError*/x); - - B.c3(num x, Object y) : super.c3(x, /*info:DownCastImplicit*/y); - } - - void main() { - A a = new A.c2(/*info:DownCastImplicit*/z, /*severe:StaticTypeError*/z); - var b = new B.c2(/*severe:StaticTypeError*/"hello", /*info:DownCastImplicit*/obj); - } - ''' - }); - - testChecker('Unbound variable', { - '/main.dart': ''' - void main() { - dynamic y = /*pass should be severe:StaticTypeError*/unboundVariable; - } - ''' - }); - - testChecker('Unbound type name', { - '/main.dart': ''' - void main() { - /*pass should be severe:StaticTypeError*/AToB y; - } - ''' - }); - - testChecker('Ground type subtyping: dynamic is top', { - '/main.dart': ''' - - class A {} - class B extends A {} - - void main() { - dynamic y; - Object o; - int i = 0; - double d = 0.0; - num n; - A a; - B b; - y = o; - y = i; - y = d; - y = n; - y = a; - y = b; - } - ''' - }); - - testChecker('Ground type subtyping: dynamic downcasts', { - '/main.dart': ''' - - class A {} - class B extends A {} - - void main() { - dynamic y; - Object o; - int i = 0; - double d = 0.0; - num n; - A a; - B b; - o = y; - i = /*info:DynamicCast*/y; - d = /*info:DynamicCast*/y; - n = /*info:DynamicCast*/y; - a = /*info:DynamicCast*/y; - b = /*info:DynamicCast*/y; - } - ''' - }); - - testChecker('Ground type subtyping: assigning a class', { - '/main.dart': ''' - - class A {} - class B extends A {} - - void main() { - dynamic y; - Object o; - int i = 0; - double d = 0.0; - num n; - A a; - B b; - y = a; - o = a; - i = /*severe:StaticTypeError*/a; - d = /*severe:StaticTypeError*/a; - n = /*severe:StaticTypeError*/a; - a = a; - b = /*info:DownCastImplicit*/a; - } - ''' - }); - - testChecker('Ground type subtyping: assigning a subclass', { - '/main.dart': ''' - - class A {} - class B extends A {} - class C extends A {} - - void main() { - dynamic y; - Object o; - int i = 0; - double d = 0.0; - num n; - A a; - B b; - C c; - y = b; - o = b; - i = /*severe:StaticTypeError*/b; - d = /*severe:StaticTypeError*/b; - n = /*severe:StaticTypeError*/b; - a = b; - b = b; - c = /*severe:StaticTypeError*/b; - } - ''' - }); - - testChecker('Ground type subtyping: interfaces', { - '/main.dart': ''' - - class A {} - class B extends A {} - class C extends A {} - class D extends B implements C {} - - void main() { - A top; - B left; - C right; - D bot; - { - top = top; - top = left; - top = right; - top = bot; - } - { - left = /*info:DownCastImplicit*/top; - left = left; - left = /*severe:StaticTypeError*/right; - left = bot; - } - { - right = /*info:DownCastImplicit*/top; - right = /*severe:StaticTypeError*/left; - right = right; - right = bot; - } - { - bot = /*info:DownCastImplicit*/top; - bot = /*info:DownCastImplicit*/left; - bot = /*info:DownCastImplicit*/right; - bot = bot; - } - } - ''' - }); - - testChecker('Function typing and subtyping: int and object', { - '/main.dart': ''' - - typedef Object Top(int x); // Top of the lattice - typedef int Left(int x); // Left branch - typedef int Left2(int x); // Left branch - typedef Object Right(Object x); // Right branch - typedef int Bot(Object x); // Bottom of the lattice - - Object top(int x) => x; - int left(int x) => x; - Object right(Object x) => x; - int _bot(Object x) => /*info:DownCastImplicit*/x; - int bot(Object x) => x as int; - - void main() { - { // Check typedef equality - Left f = left; - Left2 g = f; - } - { - Top f; - f = top; - f = left; - f = right; - f = bot; - } - { - Left f; - f = /*warning:DownCastComposite*/top; - f = left; - f = /*warning:DownCastComposite*/right; // Should we reject this? - f = bot; - } - { - Right f; - f = /*warning:DownCastComposite*/top; - f = /*warning:DownCastComposite*/left; // Should we reject this? - f = right; - f = bot; - } - { - Bot f; - f = /*warning:DownCastComposite*/top; - f = /*warning:DownCastComposite*/left; - f = /*warning:DownCastComposite*/right; - f = bot; - } - } - ''' - }); - - testChecker('Function typing and subtyping: classes', { - '/main.dart': ''' - - class A {} - class B extends A {} - - typedef A Top(B x); // Top of the lattice - typedef B Left(B x); // Left branch - typedef B Left2(B x); // Left branch - typedef A Right(A x); // Right branch - typedef B Bot(A x); // Bottom of the lattice - - B left(B x) => x; - B _bot(A x) => /*info:DownCastImplicit*/x; - B bot(A x) => x as B; - A top(B x) => x; - A right(A x) => x; - - void main() { - { // Check typedef equality - Left f = left; - Left2 g = f; - } - { - Top f; - f = top; - f = left; - f = right; - f = bot; - } - { - Left f; - f = /*warning:DownCastComposite*/top; - f = left; - f = /*warning:DownCastComposite*/right; // Should we reject this? - f = bot; - } - { - Right f; - f = /*warning:DownCastComposite*/top; - f = /*warning:DownCastComposite*/left; // Should we reject this? - f = right; - f = bot; - } - { - Bot f; - f = /*warning:DownCastComposite*/top; - f = /*warning:DownCastComposite*/left; - f = /*warning:DownCastComposite*/right; - f = bot; - } - } - ''' - }); - - testChecker('Function typing and subtyping: dynamic', { - '/main.dart': ''' - - class A {} - - typedef dynamic Top(dynamic x); // Top of the lattice - typedef dynamic Left(A x); // Left branch - typedef A Right(dynamic x); // Right branch - typedef A Bottom(A x); // Bottom of the lattice - - dynamic left(A x) => x; - A bot(A x) => x; - dynamic top(dynamic x) => x; - A right(dynamic x) => /*info:DynamicCast*/x; - - void main() { - { - Top f; - f = top; - f = left; - f = right; - f = bot; - } - { - Left f; - f = /*warning:DownCastComposite*/top; - f = left; - f = /*warning:DownCastComposite*/right; - f = bot; - } - { - Right f; - f = /*warning:DownCastComposite*/top; - f = /*warning:DownCastComposite*/left; - f = right; - f = bot; - } - { - Bottom f; - f = /*warning:DownCastComposite*/top; - f = /*warning:DownCastComposite*/left; - f = /*warning:DownCastComposite*/right; - f = bot; - } - } - ''' - }); - - testChecker('Function typing and subtyping: function literal variance', { - '/main.dart': ''' - - class A {} - class B extends A {} - - typedef T Function2(S z); - - A top(B x) => x; - B left(B x) => x; - A right(A x) => x; - B bot(A x) => x as B; - - void main() { - { - Function2 f; - f = top; - f = left; - f = right; - f = bot; - } - { - Function2 f; - f = /*warning:DownCastComposite*/top; - f = left; - f = /*warning:DownCastComposite*/right; // Should we reject this? - f = bot; - } - { - Function2 f; - f = /*warning:DownCastComposite*/top; - f = /*warning:DownCastComposite*/left; // Should we reject this? - f = right; - f = bot; - } - { - Function2 f; - f = /*warning:DownCastComposite*/top; - f = /*warning:DownCastComposite*/left; - f = /*warning:DownCastComposite*/right; - f = bot; - } - } - ''' - }); - - testChecker('Function typing and subtyping: function variable variance', { - '/main.dart': ''' - - class A {} - class B extends A {} - - typedef T Function2(S z); - - void main() { - { - Function2 top; - Function2 left; - Function2 right; - Function2 bot; - - top = right; - top = bot; - top = top; - top = left; - - left = /*warning:DownCastComposite*/top; - left = left; - left = /*warning:DownCastComposite*/right; // Should we reject this? - left = bot; - - right = /*warning:DownCastComposite*/top; - right = /*warning:DownCastComposite*/left; // Should we reject this? - right = right; - right = bot; - - bot = /*warning:DownCastComposite*/top; - bot = /*warning:DownCastComposite*/left; - bot = /*warning:DownCastComposite*/right; - bot = bot; - } - } - ''' - }); - - testChecker('Function typing and subtyping: higher order function literals', { - '/main.dart': ''' - - class A {} - class B extends A {} - - typedef T Function2(S z); - - typedef A BToA(B x); // Top of the base lattice - typedef B AToB(A x); // Bot of the base lattice - - BToA top(AToB f) => f; - AToB left(AToB f) => f; - BToA right(BToA f) => f; - AToB _bot(BToA f) => /*warning:DownCastComposite*/f; - AToB bot(BToA f) => f as AToB; - - Function2 top(AToB f) => f; - Function2 left(AToB f) => f; - Function2 right(BToA f) => f; - Function2 _bot(BToA f) => /*warning:DownCastComposite*/f; - Function2 bot(BToA f) => f as Function2; - - - BToA top(Function2 f) => f; - AToB left(Function2 f) => f; - BToA right(Function2 f) => f; - AToB _bot(Function2 f) => /*warning:DownCastComposite*/f; - AToB bot(Function2 f) => f as AToB; - - void main() { - { - Function2 f; // Top - f = top; - f = left; - f = right; - f = bot; - } - { - Function2 f; // Left - f = /*warning:DownCastComposite*/top; - f = left; - f = /*warning:DownCastComposite*/right; // Should we reject this? - f = bot; - } - { - Function2 f; // Right - f = /*warning:DownCastComposite*/top; - f = /*warning:DownCastComposite*/left; // Should we reject this? - f = right; - f = bot; - } - { - Function2 f; // Bot - f = bot; - f = /*warning:DownCastComposite*/left; - f = /*warning:DownCastComposite*/top; - f = /*warning:DownCastComposite*/left; - } - } - ''' - }); - - testChecker( - 'Function typing and subtyping: higher order function variables', { - '/main.dart': ''' - - class A {} - class B extends A {} - - typedef T Function2(S z); - - void main() { - { - Function2, Function2> top; - Function2, Function2> right; - Function2, Function2> left; - Function2, Function2> bot; - - top = right; - top = bot; - top = top; - top = left; - - left = /*warning:DownCastComposite*/top; - left = left; - left = - /*warning:DownCastComposite should be severe:StaticTypeError*/right; - left = bot; - - right = /*warning:DownCastComposite*/top; - right = - /*warning:DownCastComposite should be severe:StaticTypeError*/left; - right = right; - right = bot; - - bot = /*warning:DownCastComposite*/top; - bot = /*warning:DownCastComposite*/left; - bot = /*warning:DownCastComposite*/right; - bot = bot; - } - } - ''' - }); - - testChecker('Function typing and subtyping: named and optional parameters', { - '/main.dart': ''' - - class A {} - - typedef A FR(A x); - typedef A FO([A x]); - typedef A FN({A x}); - typedef A FRR(A x, A y); - typedef A FRO(A x, [A y]); - typedef A FRN(A x, {A n}); - typedef A FOO([A x, A y]); - typedef A FNN({A x, A y}); - typedef A FNNN({A z, A y, A x}); - - void main() { - FR r; - FO o; - FN n; - FRR rr; - FRO ro; - FRN rn; - FOO oo; - FNN nn; - FNNN nnn; - - r = r; - r = o; - r = /*severe:StaticTypeError*/n; - r = /*severe:StaticTypeError*/rr; - r = ro; - r = rn; - r = oo; - r = /*severe:StaticTypeError*/nn; - r = /*severe:StaticTypeError*/nnn; - - o = /*warning:DownCastComposite*/r; - o = o; - o = /*severe:StaticTypeError*/n; - o = /*severe:StaticTypeError*/rr; - o = /*severe:StaticTypeError*/ro; - o = /*severe:StaticTypeError*/rn; - o = oo; - o = /*severe:StaticTypeError*/nn - o = /*severe:StaticTypeError*/nnn; - - n = /*severe:StaticTypeError*/r; - n = /*severe:StaticTypeError*/o; - n = n; - n = /*severe:StaticTypeError*/rr; - n = /*severe:StaticTypeError*/ro; - n = /*severe:StaticTypeError*/rn; - n = /*severe:StaticTypeError*/oo; - n = nn; - n = nnn; - - rr = /*severe:StaticTypeError*/r; - rr = /*severe:StaticTypeError*/o; - rr = /*severe:StaticTypeError*/n; - rr = rr; - rr = ro; - rr = /*severe:StaticTypeError*/rn; - rr = oo; - rr = /*severe:StaticTypeError*/nn; - rr = /*severe:StaticTypeError*/nnn; - - ro = /*warning:DownCastComposite*/r; - ro = /*severe:StaticTypeError*/o; - ro = /*severe:StaticTypeError*/n; - ro = /*warning:DownCastComposite*/rr; - ro = ro; - ro = /*severe:StaticTypeError*/rn; - ro = oo; - ro = /*severe:StaticTypeError*/nn; - ro = /*severe:StaticTypeError*/nnn; - - rn = /*warning:DownCastComposite*/r; - rn = /*severe:StaticTypeError*/o; - rn = /*severe:StaticTypeError*/n; - rn = /*severe:StaticTypeError*/rr; - rn = /*severe:StaticTypeError*/ro; - rn = rn; - rn = /*severe:StaticTypeError*/oo; - rn = /*severe:StaticTypeError*/nn; - rn = /*severe:StaticTypeError*/nnn; - - oo = /*warning:DownCastComposite*/r; - oo = /*warning:DownCastComposite*/o; - oo = /*severe:StaticTypeError*/n; - oo = /*warning:DownCastComposite*/rr; - oo = /*warning:DownCastComposite*/ro; - oo = /*severe:StaticTypeError*/rn; - oo = oo; - oo = /*severe:StaticTypeError*/nn; - oo = /*severe:StaticTypeError*/nnn; - - nn = /*severe:StaticTypeError*/r; - nn = /*severe:StaticTypeError*/o; - nn = /*warning:DownCastComposite*/n; - nn = /*severe:StaticTypeError*/rr; - nn = /*severe:StaticTypeError*/ro; - nn = /*severe:StaticTypeError*/rn; - nn = /*severe:StaticTypeError*/oo; - nn = nn; - nn = nnn; - - nnn = /*severe:StaticTypeError*/r; - nnn = /*severe:StaticTypeError*/o; - nnn = /*warning:DownCastComposite*/n; - nnn = /*severe:StaticTypeError*/rr; - nnn = /*severe:StaticTypeError*/ro; - nnn = /*severe:StaticTypeError*/rn; - nnn = /*severe:StaticTypeError*/oo; - nnn = /*warning:DownCastComposite*/nn; - nnn = nnn; - } - ''' - }); - - testChecker('Function subtyping: objects with call methods', { - '/main.dart': ''' - - typedef int I2I(int x); - typedef num N2N(num x); - class A { - int call(int x) => x; - } - class B { - num call(num x) => x; - } - int i2i(int x) => x; - num n2n(num x) => x; - void main() { - { - I2I f; - f = new A(); - f = /*severe:StaticTypeError*/new B(); - f = i2i; - f = /*warning:DownCastComposite*/n2n; - f = /*warning:DownCastComposite*/i2i as Object; - f = /*warning:DownCastComposite*/n2n as Function; - } - { - N2N f; - f = /*severe:StaticTypeError*/new A(); - f = new B(); - f = /*warning:DownCastComposite*/i2i; - f = n2n; - f = /*warning:DownCastComposite*/i2i as Object; - f = /*warning:DownCastComposite*/n2n as Function; - } - { - A f; - f = new A(); - f = /*severe:StaticTypeError*/new B(); - f = /*severe:StaticTypeError*/i2i; - f = /*severe:StaticTypeError*/n2n; - f = /*info:DownCastImplicit*/i2i as Object; - f = /*info:DownCastImplicit*/n2n as Function; - } - { - B f; - f = /*severe:StaticTypeError*/new A(); - f = new B(); - f = /*severe:StaticTypeError*/i2i; - f = /*severe:StaticTypeError*/n2n; - f = /*info:DownCastImplicit*/i2i as Object; - f = /*info:DownCastImplicit*/n2n as Function; - } - { - Function f; - f = new A(); - f = new B(); - f = i2i; - f = n2n; - f = /*info:DownCastImplicit*/i2i as Object; - f = (n2n as Function); - } - } - ''' - }); - - testChecker('Function typing and subtyping: void', { - '/main.dart': ''' - - class A { - void bar() => null; - void foo() => bar; // allowed - } - ''' - }); - - testChecker('Relaxed casts', { - '/main.dart': ''' - - class A {} - - class L {} - class M extends L {} - // L - // / \ - // M L - // \ / - // M - // In normal Dart, there are additional edges - // from M to M - // from L to M - // from L to L - void main() { - L lOfDs; - L lOfOs; - L lOfAs; - - M mOfDs; - M mOfOs; - M mOfAs; - - { - lOfDs = mOfDs; - lOfDs = mOfOs; - lOfDs = mOfAs; - lOfDs = lOfDs; - lOfDs = lOfOs; - lOfDs = lOfAs; - } - { - lOfOs = mOfDs; - lOfOs = mOfOs; - lOfOs = mOfAs; - lOfOs = lOfDs; - lOfOs = lOfOs; - lOfOs = lOfAs; - } - { - lOfAs = /*warning:DownCastComposite*/mOfDs; - lOfAs = /*severe:StaticTypeError*/mOfOs; - lOfAs = mOfAs; - lOfAs = /*warning:DownCastComposite*/lOfDs; - lOfAs = /*warning:DownCastComposite*/lOfOs; - lOfAs = lOfAs; - } - { - mOfDs = mOfDs; - mOfDs = mOfOs; - mOfDs = mOfAs; - mOfDs = /*info:DownCastImplicit*/lOfDs; - mOfDs = /*info:DownCastImplicit*/lOfOs; - mOfDs = /*info:DownCastImplicit*/lOfAs; - } - { - mOfOs = mOfDs; - mOfOs = mOfOs; - mOfOs = mOfAs; - mOfOs = /*info:DownCastImplicit*/lOfDs; - mOfOs = /*info:DownCastImplicit*/lOfOs; - mOfOs = /*severe:StaticTypeError*/lOfAs; - } - { - mOfAs = /*warning:DownCastComposite*/mOfDs; - mOfAs = /*warning:DownCastComposite*/mOfOs; - mOfAs = mOfAs; - mOfAs = /*warning:DownCastComposite*/lOfDs; - mOfAs = /*warning:DownCastComposite*/lOfOs; - mOfAs = /*warning:DownCastComposite*/lOfAs; - } - - } - ''' - }); - - testChecker('Type checking literals', { - '/main.dart': ''' - test() { - num n = 3; - int i = 3; - String s = "hello"; - { - List l = [i]; - l = [/*severe:StaticTypeError*/s]; - l = [/*info:DownCastImplicit*/n]; - l = [i, /*info:DownCastImplicit*/n, /*severe:StaticTypeError*/s]; - } - { - List l = [i]; - l = [s]; - l = [n]; - l = [i, n, s]; - } - { - Map m = {s: i}; - m = {s: /*severe:StaticTypeError*/s}; - m = {s: /*info:DownCastImplicit*/n}; - m = {s: i, - s: /*info:DownCastImplicit*/n, - s: /*severe:StaticTypeError*/s}; - } - // TODO(leafp): We can't currently test for key errors since the - // error marker binds to the entire entry. - { - Map m = {s: i}; - m = {s: s}; - m = {s: n}; - m = {s: i, - s: n, - s: s}; - m = {i: s, - n: s, - s: s}; - } - } - ''' - }); - - testChecker('casts in constant contexts', { - '/main.dart': ''' - class A { - static const num n = 3.0; - static const int i = /*info:AssignmentCast*/n; - final int fi; - const A(num a) : this.fi = /*info:DownCastImplicit*/a; - } - class B extends A { - const B(Object a) : super(/*info:DownCastImplicit*/a); - } - void foo(Object o) { - var a = const A(/*info:DownCastImplicit*/o); - } - ''' - }); - - testChecker('casts in conditionals', { - '/main.dart': ''' - main() { - bool b = true; - num x = b ? 1 : 2.3; - int y = /*info:AssignmentCast*/b ? 1 : 2.3; - String z = !b ? "hello" : null; - z = b ? null : "hello"; - } - ''' - }); - - testChecker('redirecting constructor', { - '/main.dart': ''' - class A { - A(A x) {} - A.two() : this(/*severe:StaticTypeError*/3); - } - ''' - }); - - testChecker('super constructor', { - '/main.dart': ''' - class A { A(A x) {} } - class B extends A { - B() : super(/*severe:StaticTypeError*/3); - } - ''' - }); - - testChecker('field/field override', { - '/main.dart': ''' - class A {} - class B extends A {} - class C extends B {} - - class Base { - B f1; - B f2; - B f3; - B f4; - } - - class Child extends Base { - /*severe:InvalidMethodOverride*/A f1; // invalid for getter - /*severe:InvalidMethodOverride*/C f2; // invalid for setter - var f3; - /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/dynamic f4; - } - ''' - }); - - testChecker('getter/getter override', { - '/main.dart': ''' - class A {} - class B extends A {} - class C extends B {} - - abstract class Base { - B get f1; - B get f2; - B get f3; - B get f4; - } - - class Child extends Base { - /*severe:InvalidMethodOverride*/A get f1 => null; - C get f2 => null; - get f3 => null; - /*severe:InvalidMethodOverride*/dynamic get f4 => null; - } - ''' - }); - - testChecker('field/getter override', { - '/main.dart': ''' - class A {} - class B extends A {} - class C extends B {} - - abstract class Base { - B f1; - B f2; - B f3; - B f4; - } - - class Child extends Base { - /*severe:InvalidMethodOverride*/A get f1 => null; - C get f2 => null; - get f3 => null; - /*severe:InvalidMethodOverride*/dynamic get f4 => null; - } - ''' - }); - - testChecker('setter/setter override', { - '/main.dart': ''' - class A {} - class B extends A {} - class C extends B {} - - abstract class Base { - void set f1(B value); - void set f2(B value); - void set f3(B value); - void set f4(B value); - void set f5(B value); - } - - class Child extends Base { - void set f1(A value) {} - /*severe:InvalidMethodOverride*/void set f2(C value) {} - void set f3(value) {} - /*severe:InvalidMethodOverride*/void set f4(dynamic value) {} - set f5(B value) {} - } - ''' - }); - - testChecker('field/setter override', { - '/main.dart': ''' - class A {} - class B extends A {} - class C extends B {} - - class Base { - B f1; - B f2; - B f3; - B f4; - B f5; - } - - class Child extends Base { - B get f1 => null; - B get f2 => null; - B get f3 => null; - B get f4 => null; - B get f5 => null; - - void set f1(A value) {} - /*severe:InvalidMethodOverride*/void set f2(C value) {} - void set f3(value) {} - /*severe:InvalidMethodOverride*/void set f4(dynamic value) {} - set f5(B value) {} - } - ''' - }); - - testChecker('method override', { - '/main.dart': ''' - class A {} - class B extends A {} - class C extends B {} - - class Base { - B m1(B a); - B m2(B a); - B m3(B a); - B m4(B a); - B m5(B a); - B m6(B a); - } - - class Child extends Base { - /*severe:InvalidMethodOverride*/A m1(A value) {} - /*severe:InvalidMethodOverride*/C m2(C value) {} - /*severe:InvalidMethodOverride*/A m3(C value) {} - C m4(A value) {} - m5(value) {} - /*severe:InvalidMethodOverride*/dynamic m6(dynamic value) {} - } - ''' - }); - - testChecker('unary operators', { - '/main.dart': ''' - class A { - A operator ~() {} - A operator +(int x) {} - A operator -(int x) {} - A operator -() {} - } - - foo() => new A(); - - test() { - A a = new A(); - var c = foo(); - - ~a; - (/*info:DynamicInvoke*/~d); - - !/*severe:StaticTypeError*/a; - !/*info:DynamicCast*/d; - - -a; - (/*info:DynamicInvoke*/-d); - - ++a; - --a; - (/*info:DynamicInvoke*/++d); - (/*info:DynamicInvoke*/--d); - - a++; - a--; - (/*info:DynamicInvoke*/d++); - (/*info:DynamicInvoke*/d--); - }''' - }); - - testChecker('binary and index operators', { - '/main.dart': ''' - class A { - A operator *(B b) {} - A operator /(B b) {} - A operator ~/(B b) {} - A operator %(B b) {} - A operator +(B b) {} - A operator -(B b) {} - A operator <<(B b) {} - A operator >>(B b) {} - A operator &(B b) {} - A operator ^(B b) {} - A operator |(B b) {} - A operator[](B b) {} - } - - class B { - A operator -(B b) {} - } - - foo() => new A(); - - test() { - A a = new A(); - B b = new B(); - var c = foo(); - a = a * b; - a = a * /*info:DynamicCast*/c; - a = a / b; - a = a ~/ b; - a = a % b; - a = a + b; - a = a + /*severe:StaticTypeError*/a; - a = a - b; - b = /*severe:StaticTypeError*/b - b; - a = a << b; - a = a >> b; - a = a & b; - a = a ^ b; - a = a | b; - c = (/*info:DynamicInvoke*/c + b); - - String x = 'hello'; - int y = 42; - x = x + x; - x = x + /*info:DynamicCast*/c; - x = x + /*severe:StaticTypeError*/y; - - bool p = true; - p = p && p; - p = p && /*info:DynamicCast*/c; - p = (/*info:DynamicCast*/c) && p; - p = (/*info:DynamicCast*/c) && /*info:DynamicCast*/c; - p = (/*severe:StaticTypeError*/y) && p; - p = c == y; - - a = a[b]; - a = a[/*info:DynamicCast*/c]; - c = (/*info:DynamicInvoke*/c[b]); - a[/*severe:StaticTypeError*/y]; - } - ''' - }); - - testChecker('compound assignments', { - '/main.dart': ''' - class A { - A operator *(B b) {} - A operator /(B b) {} - A operator ~/(B b) {} - A operator %(B b) {} - A operator +(B b) {} - A operator -(B b) {} - A operator <<(B b) {} - A operator >>(B b) {} - A operator &(B b) {} - A operator ^(B b) {} - A operator |(B b) {} - D operator [](B index) {} - void operator []=(B index, D value) {} - } - - class B { - A operator -(B b) {} - } - - class D { - D operator +(D d) {} - } - - foo() => new A(); - - test() { - int x = 0; - x += 5; - (/*severe:StaticTypeError*/x += 3.14); - - double y = 0.0; - y += 5; - y += 3.14; - - num z = 0; - z += 5; - z += 3.14; - - x = /*info:DownCastImplicit*/x + z; - x += /*info:DownCastImplicit*/z; - y = /*info:DownCastImplicit*/y + z; - y += /*info:DownCastImplicit*/z; - - dynamic w = 42; - x += /*info:DynamicCast*/w; - y += /*info:DynamicCast*/w; - z += /*info:DynamicCast*/w; - - A a = new A(); - B b = new B(); - var c = foo(); - a = a * b; - a *= b; - a *= /*info:DynamicCast*/c; - a /= b; - a ~/= b; - a %= b; - a += b; - a += /*severe:StaticTypeError*/a; - a -= b; - (/*severe:StaticTypeError*/b -= b); - a <<= b; - a >>= b; - a &= b; - a ^= b; - a |= b; - (/*info:DynamicInvoke*/c += b); - - var d = new D(); - a[b] += d; - a[/*info:DynamicCast*/c] += d; - a[/*severe:StaticTypeError*/z] += d; - a[b] += /*info:DynamicCast*/c; - a[b] += /*severe:StaticTypeError*/z; - (/*info:DynamicInvoke*/(/*info:DynamicInvoke*/c[b]) += d); - } - ''' - }); - - testChecker('super call placement', { - '/main.dart': ''' - class Base { - var x; - Base() : x = print('Base.1') { print('Base.2'); } - } - - class Derived extends Base { - var y, z; - Derived() - : y = print('Derived.1'), - /*severe:InvalidSuperInvocation*/super(), - z = print('Derived.2') { - print('Derived.3'); - } - } - - class Valid extends Base { - var y, z; - Valid() - : y = print('Valid.1'), - z = print('Valid.2'), - super() { - print('Valid.3'); - } - } - - class AlsoValid extends Base { - AlsoValid() : super(); - } - - main() => new Derived(); - ''' - }); - - testChecker('for loop variable', { - '/main.dart': ''' - foo() { - for (int i = 0; i < 10; i++) { - i = /*severe:StaticTypeError*/"hi"; - } - } - bar() { - for (var i = 0; i < 10; i++) { - int j = i + 1; - } - } - ''' - }); - - group('invalid overrides', () { - testChecker('child override', { - '/main.dart': ''' - class A {} - class B {} - - class Base { - A f; - } - - class T1 extends Base { - /*severe:InvalidMethodOverride*/B get f => null; - } - - class T2 extends Base { - /*severe:InvalidMethodOverride*/set f(B b) => null; - } - - class T3 extends Base { - /*severe:InvalidMethodOverride*/final B f; - } - class T4 extends Base { - // two: one for the getter one for the setter. - /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/B f; - } - ''' - }); - - testChecker('child override 2', { - '/main.dart': ''' - class A {} - class B {} - - class Base { - m(A a) {} - } - - class Test extends Base { - /*severe:InvalidMethodOverride*/m(B a) {} - } - ''' - }); - testChecker('grandchild override', { - '/main.dart': ''' - class A {} - class B {} - - class Grandparent { - m(A a) {} - } - class Parent extends Grandparent { - } - - class Test extends Parent { - /*severe:InvalidMethodOverride*/m(B a) {} - } - ''' - }); - - testChecker('double override', { - '/main.dart': ''' - class A {} - class B {} - - class Grandparent { - m(A a) {} - } - class Parent extends Grandparent { - m(A a) {} - } - - class Test extends Parent { - // Reported only once - /*severe:InvalidMethodOverride*/m(B a) {} - } - ''' - }); - - testChecker('double override 2', { - '/main.dart': ''' - class A {} - class B {} - - class Grandparent { - m(A a) {} - } - class Parent extends Grandparent { - /*severe:InvalidMethodOverride*/m(B a) {} - } - - class Test extends Parent { - m(B a) {} - } - ''' - }); - - testChecker('mixin override to base', { - '/main.dart': ''' - class A {} - class B {} - - class Base { - m(A a) {} - } - - class M1 { - m(B a) {} - } - - class M2 {} - - class T1 extends Base with /*severe:InvalidMethodOverride*/M1 {} - class T2 extends Base with /*severe:InvalidMethodOverride*/M1, M2 {} - class T3 extends Base with M2, /*severe:InvalidMethodOverride*/M1 {} - ''' - }); - - testChecker('mixin override to mixin', { - '/main.dart': ''' - class A {} - class B {} - - class Base { - } - - class M1 { - m(B a) {} - } - - class M2 { - m(A a) {} - } - - class T1 extends Base with M1, /*severe:InvalidMethodOverride*/M2 {} - ''' - }); - - // This is a regression test for a bug in an earlier implementation were - // names were hiding errors if the first mixin override looked correct, - // but subsequent ones did not. - testChecker('no duplicate mixin override', { - '/main.dart': ''' - class A {} - class B {} - - class Base { - m(A a) {} - } - - class M1 { - m(A a) {} - } - - class M2 { - m(B a) {} - } - - class M3 { - m(B a) {} - } - - class T1 extends Base - with M1, /*severe:InvalidMethodOverride*/M2, M3 {} - ''' - }); - - testChecker('class override of interface', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I { - m(A a); - } - - class T1 implements I { - /*severe:InvalidMethodOverride*/m(B a) {} - } - ''' - }); - - testChecker('base class override to child interface', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I { - m(A a); - } - - class Base { - m(B a) {} - } - - - class T1 /*severe:InvalidMethodOverride*/extends Base implements I { - } - ''' - }); - - testChecker('mixin override of interface', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I { - m(A a); - } - - class M { - m(B a) {} - } - - class T1 extends Object with /*severe:InvalidMethodOverride*/M - implements I {} - ''' - }); - - // This is a case were it is incorrect to say that the base class - // incorrectly overrides the interface. - testChecker( - 'no errors if subclass correctly overrides base and interface', { - '/main.dart': ''' - class A {} - class B {} - - class Base { - m(A a) {} - } - - class I1 { - m(B a) {} - } - - class T1 /*severe:InvalidMethodOverride*/extends Base - implements I1 {} - - class T2 extends Base implements I1 { - /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {} - } - - class T3 extends Object with /*severe:InvalidMethodOverride*/Base - implements I1 {} - - class T4 extends Object with Base implements I1 { - /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {} - } - ''' - }); - }); - - group('class override of grand interface', () { - testChecker('interface of interface of child', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - abstract class I2 implements I1 {} - - class T1 implements I2 { - /*severe:InvalidMethodOverride*/m(B a) {} - } - ''' - }); - testChecker('superclass of interface of child', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - abstract class I2 extends I1 {} - - class T1 implements I2 { - /*severe:InvalidMethodOverride*/m(B a) {} - } - ''' - }); - testChecker('mixin of interface of child', { - '/main.dart': ''' - class A {} - class B {} - - abstract class M1 { - m(A a); - } - abstract class I2 extends Object with M1 {} - - class T1 implements I2 { - /*severe:InvalidMethodOverride*/m(B a) {} - } - ''' - }); - testChecker('interface of abstract superclass', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - abstract class Base implements I1 {} - - class T1 extends Base { - /*severe:InvalidMethodOverride*/m(B a) {} - } - ''' - }); - testChecker('interface of concrete superclass', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - - // See issue #25 - /*pass should be warning:AnalyzerError*/class Base implements I1 { - } - - class T1 extends Base { - // not reported technically because if the class is concrete, - // it should implement all its interfaces and hence it is - // sufficient to check overrides against it. - m(B a) {} - } - ''' - }); - }); - - group('mixin override of grand interface', () { - testChecker('interface of interface of child', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - abstract class I2 implements I1 {} - - class M { - m(B a) {} - } - - class T1 extends Object with /*severe:InvalidMethodOverride*/M - implements I2 { - } - ''' - }); - testChecker('superclass of interface of child', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - abstract class I2 extends I1 {} - - class M { - m(B a) {} - } - - class T1 extends Object with /*severe:InvalidMethodOverride*/M - implements I2 { - } - ''' - }); - testChecker('mixin of interface of child', { - '/main.dart': ''' - class A {} - class B {} - - abstract class M1 { - m(A a); - } - abstract class I2 extends Object with M1 {} - - class M { - m(B a) {} - } - - class T1 extends Object with /*severe:InvalidMethodOverride*/M - implements I2 { - } - ''' - }); - testChecker('interface of abstract superclass', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - abstract class Base implements I1 {} - - class M { - m(B a) {} - } - - class T1 extends Base with /*severe:InvalidMethodOverride*/M { - } - ''' - }); - testChecker('interface of concrete superclass', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - - // See issue #25 - /*pass should be warning:AnalyzerError*/class Base implements I1 { - } - - class M { - m(B a) {} - } - - class T1 extends Base with M { - } - ''' - }); - }); - - group('superclass override of grand interface', () { - testChecker('interface of interface of child', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - abstract class I2 implements I1 {} - - class Base { - m(B a) {} - } - - class T1 /*severe:InvalidMethodOverride*/extends Base - implements I2 { - } - ''' - }); - testChecker('superclass of interface of child', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - abstract class I2 extends I1 {} - - class Base { - m(B a) {} - } - - class T1 /*severe:InvalidMethodOverride*/extends Base - implements I2 { - } - ''' - }); - testChecker('mixin of interface of child', { - '/main.dart': ''' - class A {} - class B {} - - abstract class M1 { - m(A a); - } - abstract class I2 extends Object with M1 {} - - class Base { - m(B a) {} - } - - class T1 /*severe:InvalidMethodOverride*/extends Base - implements I2 { - } - ''' - }); - testChecker('interface of abstract superclass', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - - abstract class Base implements I1 { - /*severe:InvalidMethodOverride*/m(B a) {} - } - - class T1 extends Base { - // we consider the base class incomplete because it is - // abstract, so we report the error here too. - // TODO(sigmund): consider tracking overrides in a fine-grain - // manner, then this and the double-overrides would not be - // reported. - /*severe:InvalidMethodOverride*/m(B a) {} - } - ''' - }); - testChecker('interface of concrete superclass', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - - class Base implements I1 { - /*severe:InvalidMethodOverride*/m(B a) {} - } - - class T1 extends Base { - m(B a) {} - } - ''' - }); - }); - - group('no duplicate reports from overriding interfaces', () { - testChecker('type overrides same method in multiple interfaces', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - abstract class I2 implements I1 { - m(A a); - } - - class Base { - } - - class T1 implements I2 { - /*severe:InvalidMethodOverride*/m(B a) {} - } - ''' - }); - - testChecker('type and base type override same method in interface', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - - class Base { - m(B a); - } - - // Note: no error reported in `extends Base` to avoid duplicating - // the error in T1. - class T1 extends Base implements I1 { - /*severe:InvalidMethodOverride*/m(B a) {} - } - - // If there is no error in the class, we do report the error at - // the base class: - class T2 /*severe:InvalidMethodOverride*/extends Base - implements I1 { - } - ''' - }); - - testChecker('type and mixin override same method in interface', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - - class M { - m(B a); - } - - class T1 extends Object with M implements I1 { - /*severe:InvalidMethodOverride*/m(B a) {} - } - - class T2 extends Object with /*severe:InvalidMethodOverride*/M - implements I1 { - } - ''' - }); - - testChecker('two grand types override same method in interface', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - - class Grandparent { - m(B a) {} - } - - class Parent1 extends Grandparent { - m(B a) {} - } - class Parent2 extends Grandparent { - } - - // Note: otherwise both errors would be reported on this line - class T1 /*severe:InvalidMethodOverride*/extends Parent1 - implements I1 { - } - class T2 /*severe:InvalidMethodOverride*/extends Parent2 - implements I1 { - } - ''' - }); - - testChecker('two mixins override same method in interface', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - - class M1 { - m(B a) {} - } - - class M2 { - m(B a) {} - } - - // Here we want to report both, because the error location is - // different. - // TODO(sigmund): should we merge these as well? - class T1 extends Object - with /*severe:InvalidMethodOverride*/M1 - with /*severe:InvalidMethodOverride*/M2 - implements I1 { - } - ''' - }); - - testChecker('base type and mixin override same method in interface', { - '/main.dart': ''' - class A {} - class B {} - - abstract class I1 { - m(A a); - } - - class Base { - m(B a) {} - } - - class M { - m(B a) {} - } - - // Here we want to report both, because the error location is - // different. - // TODO(sigmund): should we merge these as well? - class T1 /*severe:InvalidMethodOverride*/extends Base - with /*severe:InvalidMethodOverride*/M - implements I1 { - } - ''' - }); - }); - - testChecker('invalid runtime checks', { - '/main.dart': ''' - typedef int I2I(int x); - typedef int D2I(x); - typedef int II2I(int x, int y); - typedef int DI2I(x, int y); - typedef int ID2I(int x, y); - typedef int DD2I(x, y); - - typedef I2D(int x); - typedef D2D(x); - typedef II2D(int x, int y); - typedef DI2D(x, int y); - typedef ID2D(int x, y); - typedef DD2D(x, y); - - int foo(int x) => x; - int bar(int x, int y) => x + y; - - void main() { - bool b; - b = /*info:NonGroundTypeCheckInfo*/foo is I2I; - b = /*info:NonGroundTypeCheckInfo*/foo is D2I; - b = /*info:NonGroundTypeCheckInfo*/foo is I2D; - b = foo is D2D; - - b = /*info:NonGroundTypeCheckInfo*/bar is II2I; - b = /*info:NonGroundTypeCheckInfo*/bar is DI2I; - b = /*info:NonGroundTypeCheckInfo*/bar is ID2I; - b = /*info:NonGroundTypeCheckInfo*/bar is II2D; - b = /*info:NonGroundTypeCheckInfo*/bar is DD2I; - b = /*info:NonGroundTypeCheckInfo*/bar is DI2D; - b = /*info:NonGroundTypeCheckInfo*/bar is ID2D; - b = bar is DD2D; - - // For as, the validity of checks is deferred to runtime. - Function f; - f = foo as I2I; - f = foo as D2I; - f = foo as I2D; - f = foo as D2D; - - f = bar as II2I; - f = bar as DI2I; - f = bar as ID2I; - f = bar as II2D; - f = bar as DD2I; - f = bar as DI2D; - f = bar as ID2D; - f = bar as DD2D; - } - ''' - }); - - testChecker('custom URL mappings', { - '/main.dart': ''' - import 'dart:foobar' show Baz; - main() { - print(Baz.quux); - }''' - }, customUrlMappings: { - 'dart:foobar': '$testDirectory/checker/dart_foobar.dart' - }); - - group('function modifiers', () { - testChecker('async', { - '/main.dart': ''' - import 'dart:async'; - import 'dart:math' show Random; - - dynamic x; - - foo1() async => x; - Future foo2() async => x; - Future foo3() async => (/*info:DynamicCast*/x); - Future foo4() async => (/*severe:StaticTypeError*/new Future.value(/*info:DynamicCast*/x)); - - bar1() async { return x; } - Future bar2() async { return x; } - Future bar3() async { return (/*info:DynamicCast*/x); } - Future bar4() async { return (/*severe:StaticTypeError*/new Future.value(/*info:DynamicCast*/x)); } - - int y; - Future z; - - void baz() async { - int a = /*info:DynamicCast*/await x; - int b = await y; - int c = await z; - String d = /*severe:StaticTypeError*/await z; - } - - Future get issue_264 async { - await 42; - if (new Random().nextBool()) { - return true; - } else { - return /*severe:StaticTypeError*/new Future.value(false); - } - } - ''' - }); - - testChecker('async*', { - '/main.dart': ''' - import 'dart:async'; - - dynamic x; - - bar1() async* { yield x; } - Stream bar2() async* { yield x; } - Stream bar3() async* { yield (/*info:DynamicCast*/x); } - Stream bar4() async* { yield (/*severe:StaticTypeError*/new Stream()); } - - baz1() async* { yield* (/*info:DynamicCast*/x); } - Stream baz2() async* { yield* (/*info:DynamicCast*/x); } - Stream baz3() async* { yield* (/*warning:DownCastComposite*/x); } - Stream baz4() async* { yield* new Stream(); } - Stream baz5() async* { yield* (/*info:InferredTypeAllocation*/new Stream()); } - ''' - }); - - testChecker('sync*', { - '/main.dart': ''' - import 'dart:async'; - - dynamic x; - - bar1() sync* { yield x; } - Iterable bar2() sync* { yield x; } - Iterable bar3() sync* { yield (/*info:DynamicCast*/x); } - Iterable bar4() sync* { yield (/*severe:StaticTypeError*/new Iterable()); } - - baz1() sync* { yield* (/*info:DynamicCast*/x); } - Iterable baz2() sync* { yield* (/*info:DynamicCast*/x); } - Iterable baz3() sync* { yield* (/*warning:DownCastComposite*/x); } - Iterable baz4() sync* { yield* new Iterable(); } - Iterable baz5() sync* { yield* (/*info:InferredTypeAllocation*/new Iterable()); } - ''' - }); - }); -} diff --git a/pkg/dev_compiler/test/checker/dart_foobar.dart b/pkg/dev_compiler/test/checker/dart_foobar.dart deleted file mode 100644 index 05866df839c..00000000000 --- a/pkg/dev_compiler/test/checker/dart_foobar.dart +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2015, 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. - -/// This is a test for --url-mapping option. -/// Analyzer's CustomUriResolver only supports on-disk resources, so we make -/// this file accessible. -library dart.foobar; - -class Baz { - static String quux = "hello world"; -} diff --git a/pkg/dev_compiler/test/checker/inferred_type_test.dart b/pkg/dev_compiler/test/checker/inferred_type_test.dart deleted file mode 100644 index d10fb67b54d..00000000000 --- a/pkg/dev_compiler/test/checker/inferred_type_test.dart +++ /dev/null @@ -1,1291 +0,0 @@ -// Copyright (c) 2015, 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. - -/// Tests for type inference. -library dev_compiler.test.inferred_type_test; - -import 'package:test/test.dart'; - -import '../testing.dart'; - -void main() { - // Error also expected when declared type is `int`. - testChecker('infer type on var', { - '/main.dart': ''' - test1() { - int x = 3; - x = /*severe:StaticTypeError*/"hi"; - } - ''' - }); - - // If inferred type is `int`, error is also reported - testChecker('infer type on var 2', { - '/main.dart': ''' - test2() { - var x = 3; - x = /*severe:StaticTypeError*/"hi"; - } - ''' - }); - - testChecker('No error when declared type is `num` and assigned null.', { - '/main.dart': ''' - test1() { - num x = 3; - x = null; - } - ''' - }); - - testChecker('do not infer type on dynamic', { - '/main.dart': ''' - test() { - dynamic x = 3; - x = "hi"; - } - ''' - }); - - testChecker('do not infer type when initializer is null', { - '/main.dart': ''' - test() { - var x = null; - x = "hi"; - x = 3; - } - ''' - }); - - testChecker('infer type on var from field', { - '/main.dart': ''' - class A { - int x = 0; - - test1() { - var a = x; - a = /*severe:StaticTypeError*/"hi"; - a = 3; - var b = y; - b = /*severe:StaticTypeError*/"hi"; - b = 4; - var c = z; - c = /*severe:StaticTypeError*/"hi"; - c = 4; - } - - int y; // field def after use - final z = 42; // should infer `int` - } - ''' - }); - - testChecker('infer type on var from top-level', { - '/main.dart': ''' - int x = 0; - - test1() { - var a = x; - a = /*severe:StaticTypeError*/"hi"; - a = 3; - var b = y; - b = /*severe:StaticTypeError*/"hi"; - b = 4; - var c = z; - c = /*severe:StaticTypeError*/"hi"; - c = 4; - } - - int y = 0; // field def after use - final z = 42; // should infer `int` - ''' - }); - - testChecker('do not infer field type when initializer is null', { - '/main.dart': ''' - var x = null; - var y = 3; - class A { - static var x = null; - static var y = 3; - - var x2 = null; - var y2 = 3; - } - - test() { - x = "hi"; - y = /*severe:StaticTypeError*/"hi"; - A.x = "hi"; - A.y = /*severe:StaticTypeError*/"hi"; - new A().x2 = "hi"; - new A().y2 = /*severe:StaticTypeError*/"hi"; - } - ''' - }); - - testChecker('infer from variables in non-cycle imports with flag', { - '/a.dart': ''' - var x = 2; - ''', - '/main.dart': ''' - import 'a.dart'; - var y = x; - - test1() { - x = /*severe:StaticTypeError*/"hi"; - y = /*severe:StaticTypeError*/"hi"; - } - ''' - }); - - testChecker('infer from variables in non-cycle imports with flag 2', { - '/a.dart': ''' - class A { static var x = 2; } - ''', - '/main.dart': ''' - import 'a.dart'; - class B { static var y = A.x; } - - test1() { - A.x = /*severe:StaticTypeError*/"hi"; - B.y = /*severe:StaticTypeError*/"hi"; - } - ''' - }); - - testChecker('infer from variables in cycle libs when flag is on', { - '/a.dart': ''' - import 'main.dart'; - var x = 2; // ok to infer - ''', - '/main.dart': ''' - import 'a.dart'; - var y = x; // now ok :) - - test1() { - int t = 3; - t = x; - t = y; - } - ''' - }); - - testChecker('infer from variables in cycle libs when flag is on 2', { - '/a.dart': ''' - import 'main.dart'; - class A { static var x = 2; } - ''', - '/main.dart': ''' - import 'a.dart'; - class B { static var y = A.x; } - - test1() { - int t = 3; - t = A.x; - t = B.y; - } - ''' - }); - - testChecker('can infer also from static and instance fields (flag on)', { - '/a.dart': ''' - import 'b.dart'; - class A { - static final a1 = B.b1; - final a2 = new B().b2; - } - ''', - '/b.dart': ''' - class B { - static final b1 = 1; - final b2 = 1; - } - ''', - '/main.dart': ''' - import "a.dart"; - - test1() { - int x = 0; - // inference in A now works. - x = A.a1; - x = new A().a2; - } - ''' - }); - - testChecker('inference in cycles is deterministic', { - '/a.dart': ''' - import 'b.dart'; - class A { - static final a1 = B.b1; - final a2 = new B().b2; - } - ''', - '/b.dart': ''' - class B { - static final b1 = 1; - final b2 = 1; - } - ''', - '/c.dart': ''' - import "main.dart"; // creates a cycle - - class C { - static final c1 = 1; - final c2 = 1; - } - ''', - '/e.dart': ''' - import 'a.dart'; - part 'e2.dart'; - - class E { - static final e1 = 1; - static final e2 = F.f1; - static final e3 = A.a1; - final e4 = 1; - final e5 = new F().f2; - final e6 = new A().a2; - } - ''', - '/f.dart': ''' - part 'f2.dart'; - ''', - '/e2.dart': ''' - class F { - static final f1 = 1; - final f2 = 1; - } - ''', - '/main.dart': ''' - import "a.dart"; - import "c.dart"; - import "e.dart"; - - class D { - static final d1 = A.a1 + 1; - static final d2 = C.c1 + 1; - final d3 = new A().a2; - final d4 = new C().c2; - } - - test1() { - int x = 0; - // inference in A works, it's not in a cycle - x = A.a1; - x = new A().a2; - - // Within a cycle we allow inference when the RHS is well known, but - // not when it depends on other fields within the cycle - x = C.c1; - x = D.d1; - x = D.d2; - x = new C().c2; - x = new D().d3; - x = /*info:DynamicCast*/new D().d4; - - - // Similarly if the library contains parts. - x = E.e1; - x = E.e2; - x = E.e3; - x = new E().e4; - x = /*info:DynamicCast*/new E().e5; - x = new E().e6; - x = F.f1; - x = new F().f2; - } - ''' - }); - - testChecker( - 'infer from complex expressions if the outer-most value is precise', { - '/main.dart': ''' - class A { int x; B operator+(other) {} } - class B extends A { B(ignore); } - var a = new A(); - // Note: it doesn't matter that some of these refer to 'x'. - var b = new B(x); // allocations - var c1 = [x]; // list literals - var c2 = const []; - var d = {'a': 'b'}; // map literals - var e = new A()..x = 3; // cascades - var f = 2 + 3; // binary expressions are OK if the left operand - // is from a library in a different strongest - // conected component. - var g = -3; - var h = new A() + 3; - var i = - new A(); - var j = null as B; - - test1() { - a = /*severe:StaticTypeError*/"hi"; - a = new B(3); - b = /*severe:StaticTypeError*/"hi"; - b = new B(3); - c1 = []; - c1 = /*severe:StaticTypeError*/{}; - c2 = []; - c2 = /*severe:StaticTypeError*/{}; - d = {}; - d = /*severe:StaticTypeError*/3; - e = new A(); - e = /*severe:StaticTypeError*/{}; - f = 3; - f = /*severe:StaticTypeError*/false; - g = 1; - g = /*severe:StaticTypeError*/false; - h = /*severe:StaticTypeError*/false; - h = new B(); - i = false; - j = new B(); - j = /*severe:StaticTypeError*/false; - j = /*severe:StaticTypeError*/[]; - } - ''' - }); - - // but flags can enable this behavior. - testChecker('infer if complex expressions read possibly inferred field', { - '/a.dart': ''' - class A { - var x = 3; - } - ''', - '/main.dart': ''' - import 'a.dart'; - class B { - var y = 3; - } - final t1 = new A(); - final t2 = new A().x; - final t3 = new B(); - final t4 = new B().y; - - test1() { - int i = 0; - A a; - B b; - a = t1; - i = t2; - b = t3; - i = /*info:DynamicCast*/t4; - i = new B().y; // B.y was inferred though - } - ''' - }); - - group('infer types on loop indices', () { - testChecker('foreach loop', { - '/main.dart': ''' - class Foo { - int bar = 42; - } - - test() { - var list = []; - for (var x in list) { - String y = /*severe:StaticTypeError*/x; - } - - for (dynamic x in list) { - String y = /*info:DynamicCast*/x; - } - - for (String x in /*severe:StaticTypeError*/list) { - String y = x; - } - - var z; - for(z in list) { - String y = /*info:DynamicCast*/z; - } - - Iterable iter = list; - for (Foo x in /*warning:DownCastComposite*/iter) { - var y = x; - } - - dynamic iter2 = list; - for (Foo x in /*warning:DownCastComposite*/iter2) { - var y = x; - } - - var map = {}; - // Error: map must be an Iterable. - for (var x in /*severe:StaticTypeError*/map) { - String y = /*info:DynamicCast*/x; - } - - // We're not properly inferring that map.keys is an Iterable - // and that x is a String. - for (var x in map.keys) { - String y = x; - } - } - ''' - }); - - testChecker('for loop, with inference', { - '/main.dart': ''' - test() { - for (var i = 0; i < 10; i++) { - int j = i + 1; - } - } - ''' - }); - }); - - testChecker('propagate inference to field in class', { - '/main.dart': ''' - class A { - int x = 2; - } - - test() { - var a = new A(); - A b = a; // doesn't require down cast - print(a.x); // doesn't require dynamic invoke - print(a.x + 2); // ok to use in bigger expression - } - ''' - }); - - testChecker('propagate inference to field in class dynamic warnings', { - '/main.dart': ''' - class A { - int x = 2; - } - - test() { - dynamic a = new A(); - A b = /*info:DynamicCast*/a; - print(/*info:DynamicInvoke*/a.x); - print(/*info:DynamicInvoke*/(/*info:DynamicInvoke*/a.x) + 2); - } - ''' - }); - - testChecker('propagate inference transitively', { - '/main.dart': ''' - class A { - int x = 2; - } - - test5() { - var a1 = new A(); - a1.x = /*severe:StaticTypeError*/"hi"; - - A a2 = new A(); - a2.x = /*severe:StaticTypeError*/"hi"; - } - ''' - }); - - testChecker('propagate inference transitively 2', { - '/main.dart': ''' - class A { - int x = 42; - } - - class B { - A a = new A(); - } - - class C { - B b = new B(); - } - - class D { - C c = new C(); - } - - void main() { - var d1 = new D(); - print(d1.c.b.a.x); - - D d2 = new D(); - print(d2.c.b.a.x); - } - ''' - }); - - group('infer type on overridden fields', () { - testChecker('2', { - '/main.dart': ''' - class A { - int x = 2; - } - - class B extends A { - get x => 3; - } - - foo() { - String y = /*severe:StaticTypeError*/new B().x; - int z = new B().x; - } - ''' - }); - - testChecker('4', { - '/main.dart': ''' - class A { - int x = 2; - } - - class B implements A { - get x => 3; - } - - foo() { - String y = /*severe:StaticTypeError*/new B().x; - int z = new B().x; - } - ''' - }); - }); - - group('infer types on generic instantiations', () { - testChecker('infer', { - '/main.dart': ''' - class A { - T x; - } - - class B implements A { - /*severe:InvalidMethodOverride*/dynamic get x => 3; - } - - foo() { - String y = /*info:DynamicCast*/new B().x; - int z = /*info:DynamicCast*/new B().x; - } - ''' - }); - - testChecker('3', { - '/main.dart': ''' - class A { - T x; - T w; - } - - class B implements A { - get x => 3; - get w => /*severe:StaticTypeError*/"hello"; - } - - foo() { - String y = /*severe:StaticTypeError*/new B().x; - int z = new B().x; - } - ''' - }); - - testChecker('4', { - '/main.dart': ''' - class A { - T x; - } - - class B extends A { - E y; - get x => y; - } - - foo() { - int y = /*severe:StaticTypeError*/new B().x; - String z = new B().x; - } - ''' - }); - - testChecker('5', { - '/main.dart': ''' - abstract class I { - String m(a, String f(v, T e)); - } - - abstract class A implements I { - const A(); - String m(a, String f(v, T e)); - } - - abstract class M { - int y; - } - - class B extends A implements M { - const B(); - int get y => 0; - - m(a, f(v, T e)) {} - } - - foo () { - int y = /*severe:StaticTypeError*/new B().m(null, null); - String z = new B().m(null, null); - } - ''' - }); - }); - - testChecker('infer type regardless of declaration order or cycles', { - '/b.dart': ''' - import 'main.dart'; - - class B extends A { } - ''', - '/main.dart': ''' - import 'b.dart'; - class C extends B { - get x; - } - class A { - int get x; - } - foo () { - int y = new C().x; - String y = /*severe:StaticTypeError*/new C().x; - } - ''' - }); - - // Note: this is a regression test for a non-deterministic behavior we used to - // have with inference in library cycles. If you see this test flake out, - // change `test` to `skip_test` and reopen bug #48. - testChecker('infer types on generic instantiations in library cycle', { - '/a.dart': ''' - import 'main.dart'; - abstract class I { - A m(a, String f(v, int e)); - } - ''', - '/main.dart': ''' - import 'a.dart'; - - abstract class A implements I { - const A(); - - E value; - } - - abstract class M { - int y; - } - - class B extends A implements M { - const B(); - int get y => 0; - - m(a, f(v, int e)) {} - } - - foo () { - int y = /*severe:StaticTypeError*/new B().m(null, null).value; - String z = new B().m(null, null).value; - } - ''' - }); - - group('do not infer overridden fields that explicitly say dynamic', () { - testChecker('infer', { - '/main.dart': ''' - class A { - int x = 2; - } - - class B implements A { - /*severe:InvalidMethodOverride*/dynamic get x => 3; - } - - foo() { - String y = /*info:DynamicCast*/new B().x; - int z = /*info:DynamicCast*/new B().x; - } - ''' - }); - }); - - testChecker('conflicts can happen', { - '/main.dart': ''' - class I1 { - int x; - } - class I2 extends I1 { - int y; - } - - class A { - final I1 a; - } - - class B { - final I2 a; - } - - class C1 extends A implements B { - /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a => null; - } - - // Still ambiguous - class C2 extends B implements A { - /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a => null; - } - ''' - }); - - testChecker('conflicts can happen 2', { - '/main.dart': ''' - class I1 { - int x; - } - class I2 { - int y; - } - - class I3 implements I1, I2 { - int x; - int y; - } - - class A { - final I1 a; - } - - class B { - final I2 a; - } - - class C1 extends A implements B { - I3 get a => null; - } - - class C2 extends A implements B { - /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a => null; - } - ''' - }); - - testChecker( - 'infer from RHS only if it wont conflict with overridden fields', { - '/main.dart': ''' - class A { - var x; - } - - class B extends A { - var x = 2; - } - - foo() { - String y = /*info:DynamicCast*/new B().x; - int z = /*info:DynamicCast*/new B().x; - } - ''' - }); - - testChecker( - 'infer from RHS only if it wont conflict with overridden fields 2', { - '/main.dart': ''' - class A { - final x; - } - - class B extends A { - final x = 2; - } - - foo() { - String y = /*severe:StaticTypeError*/new B().x; - int z = new B().x; - } - ''' - }); - - testChecker('infer correctly on multiple variables declared together', { - '/main.dart': ''' - class A { - var x, y = 2, z = "hi"; - } - - class B extends A { - var x = 2, y = 3, z, w = 2; - } - - foo() { - String s; - int i; - - s = /*info:DynamicCast*/new B().x; - s = /*severe:StaticTypeError*/new B().y; - s = new B().z; - s = /*severe:StaticTypeError*/new B().w; - - i = /*info:DynamicCast*/new B().x; - i = new B().y; - i = /*severe:StaticTypeError*/new B().z; - i = new B().w; - } - ''' - }); - - testChecker('infer consts transitively', { - '/b.dart': ''' - const b1 = 2; - ''', - '/a.dart': ''' - import 'main.dart'; - import 'b.dart'; - const a1 = m2; - const a2 = b1; - ''', - '/main.dart': ''' - import 'a.dart'; - const m1 = a1; - const m2 = a2; - - foo() { - int i; - i = m1; - } - ''' - }); - - testChecker('infer statics transitively', { - '/b.dart': ''' - final b1 = 2; - ''', - '/a.dart': ''' - import 'main.dart'; - import 'b.dart'; - final a1 = m2; - class A { - static final a2 = b1; - } - ''', - '/main.dart': ''' - import 'a.dart'; - final m1 = a1; - final m2 = A.a2; - - foo() { - int i; - i = m1; - } - ''' - }); - - testChecker('infer statics transitively 2', { - '/main.dart': ''' - const x1 = 1; - final x2 = 1; - final y1 = x1; - final y2 = x2; - - foo() { - int i; - i = y1; - i = y2; - } - ''' - }); - - testChecker('infer statics transitively 3', { - '/a.dart': ''' - const a1 = 3; - const a2 = 4; - class A { - a3; - } - ''', - '/main.dart': ''' - import 'a.dart' show a1, A; - import 'a.dart' as p show a2, A; - const t1 = 1; - const t2 = t1; - const t3 = a1; - const t4 = p.a2; - const t5 = A.a3; - const t6 = p.A.a3; - - foo() { - int i; - i = t1; - i = t2; - i = t3; - i = t4; - } - ''' - }); - - testChecker('infer statics with method invocations', { - '/a.dart': ''' - m3(String a, String b, [a1,a2]) {} - ''', - '/main.dart': ''' - import 'a.dart'; - class T { - static final T foo = m1(m2(m3('', ''))); - static T m1(String m) { return null; } - static String m2(e) { return ''; } - } - - - ''' - }); - - testChecker('downwards inference: miscellaneous', { - '/main.dart': ''' - typedef (T x); - class A { - Function2 x; - A(this.x); - } - void main() { - { // Variables, nested literals - var x = "hello"; - var y = 3; - void f(List> l) {}; - f(/*info:InferredTypeLiteral*/[{y: x}]); - } - { - int f(int x) {}; - A a = /*info:InferredTypeAllocation*/new A(f); - } - } - ''' - }); - - group('downwards inference on instance creations', () { - String info = 'info:InferredTypeAllocation'; - String code = ''' - class A { - S x; - T y; - A(this.x, this.y); - A.named(this.x, this.y); - } - - class B extends A { - B(S y, T x) : super(x, y); - B.named(S y, T x) : super.named(x, y); - } - - class C extends B { - C(S a) : super(a, a); - C.named(S a) : super.named(a, a); - } - - class D extends B { - D(T a) : super(a, 3); - D.named(T a) : super.named(a, 3); - } - - class E extends A, T> { - E(T a) : super(null, a); - } - - class F extends A { - F(S x, T y, {List a, List b}) : super(x, y); - F.named(S x, T y, [S a, T b]) : super(a, b); - } - - void main() { - { - A a0 = /*$info*/new A(3, "hello"); - A a1 = /*$info*/new A.named(3, "hello"); - A a2 = new A(3, "hello"); - A a3 = new A.named(3, "hello"); - A a4 = /*severe:StaticTypeError*/new A(3, "hello"); - A a5 = /*severe:StaticTypeError*/new A.named(3, "hello"); - } - { - A a0 = /*severe:StaticTypeError*/new A("hello", 3); - A a1 = /*severe:StaticTypeError*/new A.named("hello", 3); - } - { - A a0 = /*$info*/new B("hello", 3); - A a1 = /*$info*/new B.named("hello", 3); - A a2 = new B("hello", 3); - A a3 = new B.named("hello", 3); - A a4 = /*severe:StaticTypeError*/new B("hello", 3); - A a5 = /*severe:StaticTypeError*/new B.named("hello", 3); - } - { - A a0 = /*severe:StaticTypeError*/new B(3, "hello"); - A a1 = /*severe:StaticTypeError*/new B.named(3, "hello"); - } - { - A a0 = /*$info*/new C(3); - A a1 = /*$info*/new C.named(3); - A a2 = new C(3); - A a3 = new C.named(3); - A a4 = /*severe:StaticTypeError*/new C(3); - A a5 = /*severe:StaticTypeError*/new C.named(3); - } - { - A a0 = /*severe:StaticTypeError*/new C("hello"); - A a1 = /*severe:StaticTypeError*/new C.named("hello"); - } - { - A a0 = /*$info*/new D("hello"); - A a1 = /*$info*/new D.named("hello"); - A a2 = new D("hello"); - A a3 = new D.named("hello"); - A a4 = /*severe:StaticTypeError*/new D("hello"); - A a5 = /*severe:StaticTypeError*/new D.named("hello"); - } - { - A a0 = /*severe:StaticTypeError*/new D(3); - A a1 = /*severe:StaticTypeError*/new D.named(3); - } - { // Currently we only allow variable constraints. Test that we reject. - A, String> a0 = /*severe:StaticTypeError*/new E("hello"); - } - { // Check named and optional arguments - A a0 = /*$info*/new F(3, "hello", a: [3], b: ["hello"]); - A a1 = /*severe:StaticTypeError*/new F(3, "hello", a: ["hello"], b:[3]); - A a2 = /*$info*/new F.named(3, "hello", 3, "hello"); - A a3 = /*$info*/new F.named(3, "hello"); - A a4 = /*severe:StaticTypeError*/new F.named(3, "hello", "hello", 3); - A a5 = /*severe:StaticTypeError*/new F.named(3, "hello", "hello"); - } - } - '''; - testChecker('infer downwards', {'/main.dart': code}); - }); - - group('downwards inference on list literals', () { - String info = "info:InferredTypeLiteral"; - String code = ''' - void foo([List list1 = /*$info*/const [], - List list2 = /*severe:StaticTypeError*/const [42]]) { - } - - void main() { - { - List l0 = /*$info*/[]; - List l1 = /*$info*/[3]; - List l2 = /*severe:StaticTypeError*/["hello"]; - List l3 = /*severe:StaticTypeError*/["hello", 3]; - } - { - List l0 = []; - List l1 = [3]; - List l2 = ["hello"]; - List l3 = ["hello", 3]; - } - { - List l0 = /*severe:StaticTypeError*/[]; - List l1 = /*severe:StaticTypeError*/[3]; - List l2 = /*severe:StaticTypeError*/[/*severe:StaticTypeError*/"hello"]; - List l3 = /*severe:StaticTypeError*/[/*severe:StaticTypeError*/"hello", 3]; - } - { - Iterable i0 = /*$info*/[]; - Iterable i1 = /*$info*/[3]; - Iterable i2 = /*severe:StaticTypeError*/["hello"]; - Iterable i3 = /*severe:StaticTypeError*/["hello", 3]; - } - { - const List c0 = /*$info*/const []; - const List c1 = /*$info*/const [3]; - const List c2 = /*severe:StaticTypeError*/const ["hello"]; - const List c3 = /*severe:StaticTypeError*/const ["hello", 3]; - } - } - '''; - testChecker('infer downwards', {'/main.dart': code}); - }); - - group('downwards inference on function arguments', () { - String info = "info:InferredTypeLiteral"; - String code = ''' - void f0(List a) {}; - void f1({List a}) {}; - void f2(Iterable a) {}; - void f3(Iterable> a) {}; - void f4({Iterable> a}) {}; - void main() { - f0(/*$info*/[]); - f0(/*$info*/[3]); - f0(/*severe:StaticTypeError*/["hello"]); - f0(/*severe:StaticTypeError*/["hello", 3]); - - f1(a: /*$info*/[]); - f1(a: /*$info*/[3]); - f1(a: /*severe:StaticTypeError*/["hello"]); - f1(a: /*severe:StaticTypeError*/["hello", 3]); - - f2(/*$info*/[]); - f2(/*$info*/[3]); - f2(/*severe:StaticTypeError*/["hello"]); - f2(/*severe:StaticTypeError*/["hello", 3]); - - f3(/*$info*/[]); - f3(/*$info*/[[3]]); - f3(/*severe:StaticTypeError*/[["hello"]]); - f3(/*severe:StaticTypeError*/[["hello"], [3]]); - - f4(a: /*$info*/[]); - f4(a: /*$info*/[[3]]); - f4(a: /*severe:StaticTypeError*/[["hello"]]); - f4(a: /*severe:StaticTypeError*/[["hello"], [3]]); - } - '''; - testChecker('infer downwards', {'/main.dart': code}); - }); - - group('downwards inference on map literals', () { - String info = "info:InferredTypeLiteral"; - String code = ''' - void foo([Map m1 = /*$info*/const {1: "hello"}, - Map m1 = /*severe:StaticTypeError*/const {"hello": "world"}]) { - } - void main() { - { - Map l0 = /*$info*/{}; - Map l1 = /*$info*/{3: "hello"}; - Map l2 = /*severe:StaticTypeError*/{"hello": "hello"}; - Map l3 = /*severe:StaticTypeError*/{3: 3}; - Map l4 = /*severe:StaticTypeError*/{3:"hello", "hello": 3}; - } - { - Map l0 = {}; - Map l1 = {3: "hello"}; - Map l2 = {"hello": "hello"}; - Map l3 = {3: 3}; - Map l4 = {3:"hello", "hello": 3}; - } - { - Map l0 = /*$info*/{}; - Map l1 = /*$info*/{3: "hello"}; - Map l2 = /*$info*/{"hello": "hello"}; - Map l3 = /*severe:StaticTypeError*/{3: 3}; - Map l4 = /*severe:StaticTypeError*/{3:"hello", "hello": 3}; - } - { - Map l0 = /*$info*/{}; - Map l1 = /*$info*/{3: "hello"}; - Map l2 = /*severe:StaticTypeError*/{"hello": "hello"}; - Map l3 = /*$info*/{3: 3}; - Map l3 = /*severe:StaticTypeError*/{3:"hello", "hello": 3}; - } - { - Map l0 = /*severe:StaticTypeError*/{}; - Map l1 = /*severe:StaticTypeError*/{3: "hello"}; - Map l3 = /*severe:StaticTypeError*/{3: 3}; - } - { - const Map l0 = /*$info*/const {}; - const Map l1 = /*$info*/const {3: "hello"}; - const Map l2 = /*severe:StaticTypeError*/const {"hello": "hello"}; - const Map l3 = /*severe:StaticTypeError*/const {3: 3}; - const Map l4 = /*severe:StaticTypeError*/const {3:"hello", "hello": 3}; - } - } - '''; - testChecker('infer downwards', {'/main.dart': code}); - }); - - testChecker('downwards inference on function expressions', { - '/main.dart': ''' - typedef T Function2(S x); - - void main () { - { - Function2 l0 = (int x) => null; - Function2 l1 = (int x) => "hello"; - Function2 l2 = /*severe:StaticTypeError*/(String x) => "hello"; - Function2 l3 = /*severe:StaticTypeError*/(int x) => 3; - Function2 l4 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) {return 3}; - } - { - Function2 l0 = /*info:InferredTypeClosure*/(x) => null; - Function2 l1 = /*info:InferredTypeClosure*/(x) => "hello"; - Function2 l2 = /*severe:StaticTypeError*/(x) => 3; - Function2 l3 = /*warning:UninferredClosure should be severe:StaticTypeError*/(x) {return 3}; - } - { - Function2> l0 = (int x) => null; - Function2> l1 = /*info:InferredTypeClosure*/(int x) => ["hello"]; - Function2> l2 = /*severe:StaticTypeError*/(String x) => ["hello"]; - Function2> l3 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) => [3]; - Function2> l4 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) {return [3]}; - } - { - Function2 l0 = /*info:InferredTypeClosure*/(x) => x; - Function2 l1 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x+1; - Function2 l2 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => x; - Function2 l3 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3); - Function2 l4 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3); - } - } - ''' - }); - - testChecker('inferred initializing formal checks default value', { - '/main.dart': ''' - class Foo { - var x = 1; - Foo([this.x = /*severe:StaticTypeError*/"1"]); - }''' - }); - - group('quasi-generics', () { - testChecker('dart:math min/max', { - '/main.dart': ''' - import 'dart:math'; - - void printInt(int x) => print(x); - void printDouble(double x) => print(x); - - num myMax(num x, num y) => max(x, y); - - main() { - // Okay if static types match. - printInt(max(1, 2)); - printInt(min(1, 2)); - printDouble(max(1.0, 2.0)); - printDouble(min(1.0, 2.0)); - - // No help for user-defined functions from num->num->num. - printInt(/*info:DownCastImplicit*/myMax(1, 2)); - printInt(myMax(1, 2) as int); - - // Mixing int and double means return type is num. - printInt(/*info:DownCastImplicit*/max(1, 2.0)); - printInt(/*info:DownCastImplicit*/min(1, 2.0)); - printDouble(/*info:DownCastImplicit*/max(1, 2.0)); - printDouble(/*info:DownCastImplicit*/min(1, 2.0)); - - // Types other than int and double are not accepted. - printInt( - /*info:DownCastImplicit*/min( - /*severe:StaticTypeError*/"hi", - /*severe:StaticTypeError*/"there")); - } - ''' - }); - - testChecker('Iterable and Future', { - '/main.dart': ''' - import 'dart:async'; - - Future make(int x) => (/*info:InferredTypeAllocation*/new Future(() => x)); - - main() { - Iterable> list = [1, 2, 3].map(make); - Future> results = Future.wait(list); - Future results2 = results.then((List list) - => list.fold('', (String x, int y) => x + y.toString())); - } - ''' - }); - }); -} diff --git a/pkg/dev_compiler/test/checker/self_host_test.dart b/pkg/dev_compiler/test/checker/self_host_test.dart deleted file mode 100644 index a909d06fac9..00000000000 --- a/pkg/dev_compiler/test/checker/self_host_test.dart +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2015, 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. - -/// Tests that run the checker end-to-end using the file system. -library dev_compiler.test.checker.self_host_test; - -import 'package:dev_compiler/devc.dart' show BatchCompiler; -import 'package:dev_compiler/src/options.dart'; -import 'package:test/test.dart'; -import '../testing.dart' show testDirectory, realSdkContext; - -void main() { - test('checker can run on itself ', () { - new BatchCompiler(realSdkContext, new CompilerOptions()) - .compileFromUriString('$testDirectory/all_tests.dart'); - }, skip: 'test is very slow'); -} diff --git a/pkg/dev_compiler/test/codegen_test.dart b/pkg/dev_compiler/test/codegen_test.dart index dac69944d46..66e41c82ffa 100644 --- a/pkg/dev_compiler/test/codegen_test.dart +++ b/pkg/dev_compiler/test/codegen_test.dart @@ -17,7 +17,6 @@ import 'package:path/path.dart' as path; import 'package:test/test.dart'; import 'package:dev_compiler/devc.dart'; -import 'package:dev_compiler/strong_mode.dart'; import 'package:dev_compiler/src/compiler.dart' show defaultRuntimeFiles; import 'package:dev_compiler/src/options.dart'; @@ -184,7 +183,6 @@ $compilerMessages'''; test('devc dart:core', () { var testSdkContext = createAnalysisContextWithSources( - new StrongModeOptions(), new SourceResolverOptions( dartSdkPath: path.join(testDirectory, '..', 'tool', 'generated_sdk'))); diff --git a/pkg/dev_compiler/test/dependency_graph_test.dart b/pkg/dev_compiler/test/dependency_graph_test.dart index 6b9a36da709..ecc09184529 100644 --- a/pkg/dev_compiler/test/dependency_graph_test.dart +++ b/pkg/dev_compiler/test/dependency_graph_test.dart @@ -65,8 +65,7 @@ void main() { /// tests (since some tests modify the state of the files). testResourceProvider = createTestResourceProvider(testFiles); testUriResolver = new ResourceUriResolver(testResourceProvider); - context = createAnalysisContextWithSources( - options.strongOptions, options.sourceOptions, + context = createAnalysisContextWithSources(options.sourceOptions, fileResolvers: [testUriResolver]); graph = new SourceGraph(context, new LogReporter(context), options); }); @@ -685,8 +684,7 @@ void main() { runtimeDir: '/dev_compiler_runtime/', sourceOptions: new SourceResolverOptions(useMockSdk: true), serverMode: true); - context = createAnalysisContextWithSources( - opts.strongOptions, opts.sourceOptions, + context = createAnalysisContextWithSources(opts.sourceOptions, fileResolvers: [testUriResolver]); graph = new SourceGraph(context, new LogReporter(context), opts); }); @@ -1165,8 +1163,7 @@ void main() { group('null for non-existing files', () { setUp(() { - context = createAnalysisContextWithSources( - options.strongOptions, options.sourceOptions, + context = createAnalysisContextWithSources(options.sourceOptions, fileResolvers: [testUriResolver]); graph = new SourceGraph(context, new LogReporter(context), options); }); diff --git a/pkg/dev_compiler/test/end_to_end_test.dart b/pkg/dev_compiler/test/end_to_end_test.dart index 7515240816d..b3b8d276051 100644 --- a/pkg/dev_compiler/test/end_to_end_test.dart +++ b/pkg/dev_compiler/test/end_to_end_test.dart @@ -13,7 +13,7 @@ import 'testing.dart' show realSdkContext, testDirectory; main() { var mockSdkContext = createAnalysisContextWithSources( - new StrongModeOptions(), new SourceResolverOptions(useMockSdk: true)); + new SourceResolverOptions(useMockSdk: true)); var compiler = new BatchCompiler(mockSdkContext, new CompilerOptions()); _check(file) => compiler.compileFromUriString('$testDirectory/$file.dart'); diff --git a/pkg/dev_compiler/test/report_test.dart b/pkg/dev_compiler/test/report_test.dart index 6c929ec26f8..9b4ffa26acc 100644 --- a/pkg/dev_compiler/test/report_test.dart +++ b/pkg/dev_compiler/test/report_test.dart @@ -8,7 +8,6 @@ library dev_compiler.test.report_test; import 'package:test/test.dart'; import 'package:dev_compiler/devc.dart'; -import 'package:dev_compiler/strong_mode.dart' show StrongModeOptions; import 'package:dev_compiler/src/analysis_context.dart'; import 'package:dev_compiler/src/options.dart'; @@ -38,9 +37,8 @@ void main() { var provider = createTestResourceProvider(files); var uriResolver = new TestUriResolver(provider); var srcOpts = new SourceResolverOptions(useMockSdk: true); - var context = createAnalysisContextWithSources( - new StrongModeOptions(), srcOpts, - fileResolvers: [uriResolver]); + var context = + createAnalysisContextWithSources(srcOpts, fileResolvers: [uriResolver]); var reporter = new SummaryReporter(context); new BatchCompiler(context, new CompilerOptions(sourceOptions: srcOpts), reporter: reporter).compileFromUriString('/main.dart'); diff --git a/pkg/dev_compiler/test/testing.dart b/pkg/dev_compiler/test/testing.dart index faa90be4042..a633cd3101b 100644 --- a/pkg/dev_compiler/test/testing.dart +++ b/pkg/dev_compiler/test/testing.dart @@ -7,39 +7,29 @@ library dev_compiler.src.testing; import 'dart:mirrors'; import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/file_system/memory_file_system.dart'; -import 'package:analyzer/src/generated/ast.dart'; import 'package:analyzer/src/generated/engine.dart' show AnalysisContext, AnalysisEngine, AnalysisOptionsImpl; -import 'package:analyzer/src/generated/error.dart'; import 'package:analyzer/src/generated/source.dart'; import 'package:cli_util/cli_util.dart' show getSdkDir; -import 'package:logging/logging.dart'; import 'package:path/path.dart' as path; -import 'package:source_span/source_span.dart'; -import 'package:test/test.dart'; -import 'package:dev_compiler/strong_mode.dart'; import 'package:dev_compiler/src/analysis_context.dart'; import 'package:dev_compiler/src/server/dependency_graph.dart' show runtimeFilesForServerMode; -import 'package:dev_compiler/src/info.dart'; import 'package:dev_compiler/src/options.dart'; -import 'package:dev_compiler/src/utils.dart'; /// Shared analysis context used for compilation. final AnalysisContext realSdkContext = () { - var context = createAnalysisContextWithSources( - new StrongModeOptions(), - new SourceResolverOptions( - dartSdkPath: getSdkDir().path, - customUrlMappings: { - 'package:expect/expect.dart': _testCodegenPath('expect.dart'), - 'package:async_helper/async_helper.dart': - _testCodegenPath('async_helper.dart'), - 'package:unittest/unittest.dart': _testCodegenPath('unittest.dart'), - 'package:dom/dom.dart': _testCodegenPath('sunflower', 'dom.dart') - })); + var context = createAnalysisContextWithSources(new SourceResolverOptions( + dartSdkPath: getSdkDir().path, + customUrlMappings: { + 'package:expect/expect.dart': _testCodegenPath('expect.dart'), + 'package:async_helper/async_helper.dart': + _testCodegenPath('async_helper.dart'), + 'package:unittest/unittest.dart': _testCodegenPath('unittest.dart'), + 'package:dom/dom.dart': _testCodegenPath('sunflower', 'dom.dart') + })); (context.analysisOptions as AnalysisOptionsImpl).cacheSize = 512; return context; }(); @@ -52,71 +42,6 @@ final String testDirectory = class _TestUtils {} -/// Run the checker on a program with files contents as indicated in -/// [testFiles]. -/// -/// This function makes several assumptions to make it easier to describe error -/// expectations: -/// -/// * a file named `/main.dart` exists in [testFiles]. -/// * all expected failures are listed in the source code using comments -/// immediately in front of the AST node that should contain the error. -/// * errors are formatted as a token `level:Type`, where `level` is the -/// logging level were the error would be reported at, and `Type` is the -/// concrete subclass of [StaticInfo] that denotes the error. -/// -/// For example, to check that an assignment produces a warning about a boxing -/// conversion, you can describe the test as follows: -/// -/// testChecker({ -/// '/main.dart': ''' -/// testMethod() { -/// dynamic x = /*warning:Box*/3; -/// } -/// ''' -/// }); -/// -void testChecker(String name, Map testFiles, - {String sdkDir, customUrlMappings: const {}}) { - test(name, () { - expect(testFiles.containsKey('/main.dart'), isTrue, - reason: '`/main.dart` is missing in testFiles'); - - var provider = createTestResourceProvider(testFiles); - var uriResolver = new TestUriResolver(provider); - // Enable task model strong mode - AnalysisEngine.instance.useTaskModel = true; - var context = AnalysisEngine.instance.createAnalysisContext(); - context.analysisOptions.strongMode = true; - context.sourceFactory = createSourceFactory( - new SourceResolverOptions( - customUrlMappings: customUrlMappings, - useMockSdk: sdkDir == null, - dartSdkPath: sdkDir), - fileResolvers: [uriResolver]); - - var checker = - new StrongChecker(context, new StrongModeOptions(hints: true)); - - // Run the checker on /main.dart. - var mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart')); - var initialLibrary = - context.resolveCompilationUnit2(mainSource, mainSource); - - // Extract expectations from the comments in the test files, and - // check that all errors we emit are included in the expected map. - var allLibraries = reachableLibraries(initialLibrary.element.library); - for (var lib in allLibraries) { - for (var unit in lib.units) { - if (unit.source.uri.scheme == 'dart') continue; - - var errorInfo = checker.computeErrors(unit.source); - new _ExpectedErrorVisitor(errorInfo.errors).validate(unit.unit); - } - } - }); -} - /// Creates a [MemoryResourceProvider] with test data MemoryResourceProvider createTestResourceProvider( Map testFiles) { @@ -150,131 +75,3 @@ class TestUriResolver extends ResourceUriResolver { return super.resolveAbsolute(uri, actualUri); } } - -class _ExpectedErrorVisitor extends UnifyingAstVisitor { - final Set _actualErrors; - CompilationUnit _unit; - String _unitSourceCode; - - _ExpectedErrorVisitor(List actualErrors) - : _actualErrors = new Set.from(actualErrors); - - validate(CompilationUnit unit) { - _unit = unit; - // This reads the file. Only safe because tests use MemoryFileSystem. - _unitSourceCode = unit.element.source.contents.data; - - // Visit the compilation unit. - unit.accept(this); - - if (_actualErrors.isNotEmpty) { - var actualMsgs = _actualErrors.map(_formatActualError).join('\n'); - fail('Unexpected errors reported by checker:\n\n$actualMsgs'); - } - } - - visitNode(AstNode node) { - var token = node.beginToken; - var comment = token.precedingComments; - // Use error marker found in an immediately preceding comment, - // and attach it to the outermost expression that starts at that token. - if (comment != null) { - while (comment.next != null) { - comment = comment.next; - } - if (comment.end == token.offset && node.parent.beginToken != token) { - var commentText = '$comment'; - var start = commentText.lastIndexOf('/*'); - var end = commentText.lastIndexOf('*/'); - if (start != -1 && end != -1) { - expect(start, lessThan(end)); - var errors = commentText.substring(start + 2, end).split(','); - var expectations = - errors.map(_ErrorExpectation.parse).where((x) => x != null); - - for (var e in expectations) _expectError(node, e); - } - } - } - return super.visitNode(node); - } - - void _expectError(AstNode node, _ErrorExpectation expected) { - // See if we can find the expected error in our actual errors - for (var actual in _actualErrors) { - if (actual.offset == node.offset && actual.length == node.length) { - var actualMsg = _formatActualError(actual); - expect(_actualErrorLevel(actual), expected.level, - reason: 'expected different error code at:\n\n$actualMsg'); - expect(errorCodeName(actual.errorCode), expected.typeName, - reason: 'expected different error type at:\n\n$actualMsg'); - - // We found it. Stop the search. - _actualErrors.remove(actual); - return; - } - } - - var span = _createSpan(node.offset, node.length); - var levelName = expected.level.name.toLowerCase(); - var msg = span.message(expected.typeName, color: colorOf(levelName)); - fail('expected error was not reported at:\n\n$levelName: $msg'); - } - - Level _actualErrorLevel(AnalysisError actual) { - return const { - ErrorSeverity.ERROR: Level.SEVERE, - ErrorSeverity.WARNING: Level.WARNING, - ErrorSeverity.INFO: Level.INFO - }[actual.errorCode.errorSeverity]; - } - - String _formatActualError(AnalysisError actual) { - var span = _createSpan(actual.offset, actual.length); - var levelName = _actualErrorLevel(actual).name.toLowerCase(); - var msg = span.message(actual.message, color: colorOf(levelName)); - return '$levelName: [${errorCodeName(actual.errorCode)}] $msg'; - } - - SourceSpan _createSpan(int offset, int len) { - return createSpanHelper(_unit.lineInfo, offset, offset + len, - _unit.element.source, _unitSourceCode); - } -} - -/// Describes an expected message that should be produced by the checker. -class _ErrorExpectation { - final Level level; - final String typeName; - _ErrorExpectation(this.level, this.typeName); - - static _ErrorExpectation _parse(String descriptor) { - var tokens = descriptor.split(':'); - expect(tokens.length, 2, reason: 'invalid error descriptor'); - var name = tokens[0].toUpperCase(); - var typeName = tokens[1]; - - var level = - Level.LEVELS.firstWhere((l) => l.name == name, orElse: () => null); - expect(level, isNotNull, - reason: 'invalid level in error descriptor: `${tokens[0]}`'); - expect(typeName, isNotNull, - reason: 'invalid type in error descriptor: ${tokens[1]}'); - return new _ErrorExpectation(level, typeName); - } - - static _ErrorExpectation parse(String descriptor) { - descriptor = descriptor.trim(); - var tokens = descriptor.split(' '); - if (tokens.length == 1) return _parse(tokens[0]); - expect(tokens.length, 4, reason: 'invalid error descriptor'); - expect(tokens[1], "should", reason: 'invalid error descriptor'); - expect(tokens[2], "be", reason: 'invalid error descriptor'); - if (tokens[0] == "pass") return null; - // TODO(leafp) For now, we just use whatever the current expectation is, - // eventually we could do more automated reporting here. - return _parse(tokens[0]); - } - - String toString() => '$level $typeName'; -}