Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(464)

Unified Diff: sdk/lib/_internal/compiler/implementation/typechecker.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/typechecker.dart
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
deleted file mode 100644
index b1fb8cd434fc7613472b666e0482a5b58f8e88e3..0000000000000000000000000000000000000000
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ /dev/null
@@ -1,1786 +0,0 @@
-// Copyright (c) 2012, 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.
-
-part of dart2js;
-
-class TypeCheckerTask extends CompilerTask {
- TypeCheckerTask(Compiler compiler) : super(compiler);
- String get name => "Type checker";
-
- void check(TreeElements elements) {
- AstElement element = elements.analyzedElement;
- compiler.withCurrentElement(element, () {
- measure(() {
- Node tree = element.node;
- TypeCheckerVisitor visitor =
- new TypeCheckerVisitor(compiler, elements, compiler.types);
- if (element.isField) {
- visitor.analyzingInitializer = true;
- }
- tree.accept(visitor);
- });
- });
- }
-}
-
-/**
- * Class used to report different warnings for differrent kinds of members.
- */
-class MemberKind {
- static const MemberKind METHOD = const MemberKind("method");
- static const MemberKind OPERATOR = const MemberKind("operator");
- static const MemberKind GETTER = const MemberKind("getter");
- static const MemberKind SETTER = const MemberKind("setter");
-
- final String name;
-
- const MemberKind(this.name);
-
- String toString() => name;
-}
-
-/**
- * [ElementAccess] represents the access of [element], either as a property
- * access or invocation.
- */
-abstract class ElementAccess {
- Element get element;
-
- DartType computeType(Compiler compiler);
-
- /// Returns [: true :] if the element can be access as an invocation.
- bool isCallable(Compiler compiler) {
- if (element != null && element.isAbstractField) {
- AbstractFieldElement abstractFieldElement = element;
- if (abstractFieldElement.getter == null) {
- // Setters cannot be invoked as function invocations.
- return false;
- }
- }
- return compiler.types.isAssignable(
- computeType(compiler), compiler.functionClass.computeType(compiler));
- }
-}
-
-/// An access of a instance member.
-class MemberAccess extends ElementAccess {
- final MemberSignature member;
-
- MemberAccess(MemberSignature this.member);
-
- Element get element => member.declarations.first.element;
-
- DartType computeType(Compiler compiler) => member.type;
-
- String toString() => 'MemberAccess($member)';
-}
-
-/// An access of an unresolved element.
-class DynamicAccess implements ElementAccess {
- const DynamicAccess();
-
- Element get element => null;
-
- DartType computeType(Compiler compiler) => const DynamicType();
-
- bool isCallable(Compiler compiler) => true;
-
- String toString() => 'DynamicAccess';
-}
-
-/// An access of the `assert` method.
-class AssertAccess implements ElementAccess {
- const AssertAccess();
-
- Element get element => null;
-
- DartType computeType(Compiler compiler) {
- return new FunctionType.synthesized(
- const VoidType(),
- <DartType>[const DynamicType()]);
- }
-
- bool isCallable(Compiler compiler) => true;
-
- String toString() => 'AssertAccess';
-}
-
-/**
- * An access of a resolved top-level or static property or function, or an
- * access of a resolved element through [:this:].
- */
-class ResolvedAccess extends ElementAccess {
- final Element element;
-
- ResolvedAccess(Element this.element) {
- assert(element != null);
- }
-
- DartType computeType(Compiler compiler) {
- if (element.isGetter) {
- FunctionType functionType = element.computeType(compiler);
- return functionType.returnType;
- } else if (element.isSetter) {
- FunctionType functionType = element.computeType(compiler);
- if (functionType.parameterTypes.length != 1) {
- // TODO(johnniwinther,karlklose): this happens for malformed static
- // setters. Treat them the same as instance members.
- return const DynamicType();
- }
- return functionType.parameterTypes.first;
- } else {
- return element.computeType(compiler);
- }
- }
-
- String toString() => 'ResolvedAccess($element)';
-}
-
-/// An access to a promoted variable.
-class PromotedAccess extends ElementAccess {
- final VariableElement element;
- final DartType type;
-
- PromotedAccess(VariableElement this.element, DartType this.type) {
- assert(element != null);
- assert(type != null);
- }
-
- DartType computeType(Compiler compiler) => type;
-
- String toString() => 'PromotedAccess($element,$type)';
-}
-
-/**
- * An access of a resolved top-level or static property or function, or an
- * access of a resolved element through [:this:].
- */
-class TypeAccess extends ElementAccess {
- final DartType type;
- TypeAccess(DartType this.type) {
- assert(type != null);
- }
-
- Element get element => type.element;
-
- DartType computeType(Compiler compiler) => type;
-
- String toString() => 'TypeAccess($type)';
-}
-
-/**
- * An access of a type literal.
- */
-class TypeLiteralAccess extends ElementAccess {
- final DartType type;
-
- TypeLiteralAccess(this.type) {
- assert(type != null);
- }
-
- Element get element => type.element;
-
- DartType computeType(Compiler compiler) => compiler.typeClass.rawType;
-
- String toString() => 'TypeLiteralAccess($type)';
-}
-
-
-/// An access to the 'call' method of a function type.
-class FunctionCallAccess implements ElementAccess {
- final Element element;
- final DartType type;
-
- const FunctionCallAccess(this.element, this.type);
-
- DartType computeType(Compiler compiler) => type;
-
- bool isCallable(Compiler compiler) => true;
-
- String toString() => 'FunctionAccess($element, $type)';
-}
-
-
-/// An is-expression that potentially promotes a variable.
-class TypePromotion {
- final Send node;
- final VariableElement variable;
- final DartType type;
- final List<TypePromotionMessage> messages = <TypePromotionMessage>[];
-
- TypePromotion(this.node, this.variable, this.type);
-
- bool get isValid => messages.isEmpty;
-
- TypePromotion copy() {
- return new TypePromotion(node, variable, type)..messages.addAll(messages);
- }
-
- void addHint(Spannable spannable, MessageKind kind, [Map arguments]) {
- messages.add(new TypePromotionMessage(api.Diagnostic.HINT,
- spannable, kind, arguments));
- }
-
- void addInfo(Spannable spannable, MessageKind kind, [Map arguments]) {
- messages.add(new TypePromotionMessage(api.Diagnostic.INFO,
- spannable, kind, arguments));
- }
-
- String toString() {
- return 'Promote ${variable} to ${type}${isValid ? '' : ' (invalid)'}';
- }
-}
-
-/// A hint or info message attached to a type promotion.
-class TypePromotionMessage {
- api.Diagnostic diagnostic;
- Spannable spannable;
- MessageKind messageKind;
- Map messageArguments;
-
- TypePromotionMessage(this.diagnostic, this.spannable, this.messageKind,
- [this.messageArguments]);
-}
-
-class TypeCheckerVisitor extends Visitor<DartType> {
- final Compiler compiler;
- final TreeElements elements;
- final Types types;
-
- Node lastSeenNode;
- DartType expectedReturnType;
- AsyncMarker currentAsyncMarker = AsyncMarker.SYNC;
-
- final ClassElement currentClass;
-
- InterfaceType thisType;
- InterfaceType superType;
-
- Link<DartType> cascadeTypes = const Link<DartType>();
-
- bool analyzingInitializer = false;
-
- DartType intType;
- DartType doubleType;
- DartType boolType;
- DartType stringType;
- DartType objectType;
- DartType listType;
-
- Map<Node, List<TypePromotion>> shownTypePromotionsMap =
- new Map<Node, List<TypePromotion>>();
-
- Map<VariableElement, Link<TypePromotion>> typePromotionsMap =
- new Map<VariableElement, Link<TypePromotion>>();
-
- Set<TypePromotion> reportedTypePromotions = new Set<TypePromotion>();
-
- void showTypePromotion(Node node, TypePromotion typePromotion) {
- List<TypePromotion> shownTypePromotions =
- shownTypePromotionsMap.putIfAbsent(node, () => <TypePromotion>[]);
- shownTypePromotions.add(typePromotion);
- }
-
- void registerKnownTypePromotion(TypePromotion typePromotion) {
- VariableElement variable = typePromotion.variable;
- Link<TypePromotion> knownTypes =
- typePromotionsMap.putIfAbsent(variable,
- () => const Link<TypePromotion>());
- typePromotionsMap[variable] = knownTypes.prepend(typePromotion);
- }
-
- void unregisterKnownTypePromotion(TypePromotion typePromotion) {
- VariableElement variable = typePromotion.variable;
- Link<TypePromotion> knownTypes = typePromotionsMap[variable].tail;
- if (knownTypes.isEmpty) {
- typePromotionsMap.remove(variable);
- } else {
- typePromotionsMap[variable] = knownTypes;
- }
- }
-
- List<TypePromotion> getShownTypePromotionsFor(Node node) {
- List<TypePromotion> shownTypePromotions = shownTypePromotionsMap[node];
- return shownTypePromotions != null ? shownTypePromotions : const [];
- }
-
- TypePromotion getKnownTypePromotion(VariableElement element) {
- Link<TypePromotion> promotions = typePromotionsMap[element];
- if (promotions != null) {
- while (!promotions.isEmpty) {
- TypePromotion typePromotion = promotions.head;
- if (typePromotion.isValid) {
- return typePromotion;
- }
- promotions = promotions.tail;
- }
- }
- return null;
- }
-
- DartType getKnownType(VariableElement element) {
- TypePromotion typePromotion = getKnownTypePromotion(element);
- if (typePromotion != null) return typePromotion.type;
- return element.type;
- }
-
- TypeCheckerVisitor(this.compiler, TreeElements elements, this.types)
- : this.elements = elements,
- currentClass = elements.analyzedElement != null
- ? elements.analyzedElement.enclosingClass : null {
- intType = compiler.intClass.computeType(compiler);
- doubleType = compiler.doubleClass.computeType(compiler);
- boolType = compiler.boolClass.computeType(compiler);
- stringType = compiler.stringClass.computeType(compiler);
- objectType = compiler.objectClass.computeType(compiler);
- listType = compiler.listClass.computeType(compiler);
-
- if (currentClass != null) {
- thisType = currentClass.thisType;
- superType = currentClass.supertype;
- }
- }
-
- LibraryElement get currentLibrary => elements.analyzedElement.library;
-
- reportTypeWarning(Spannable spannable, MessageKind kind,
- [Map arguments = const {}]) {
- compiler.reportWarning(spannable, kind, arguments);
- }
-
- reportTypeInfo(Spannable spannable, MessageKind kind,
- [Map arguments = const {}]) {
- compiler.reportInfo(spannable, kind, arguments);
- }
-
- reportTypePromotionHint(TypePromotion typePromotion) {
- if (!reportedTypePromotions.contains(typePromotion)) {
- reportedTypePromotions.add(typePromotion);
- for (TypePromotionMessage message in typePromotion.messages) {
- switch (message.diagnostic) {
- case api.Diagnostic.HINT:
- compiler.reportHint(message.spannable,
- message.messageKind,
- message.messageArguments);
- break;
- case api.Diagnostic.INFO:
- compiler.reportInfo(message.spannable,
- message.messageKind,
- message.messageArguments);
- break;
- }
- }
- }
- }
-
- // TODO(karlklose): remove these functions.
- DartType unhandledExpression() => const DynamicType();
-
- DartType analyzeNonVoid(Node node) {
- DartType type = analyze(node);
- if (type.isVoid) {
- reportTypeWarning(node, MessageKind.VOID_EXPRESSION);
- }
- return type;
- }
-
- DartType analyzeWithDefault(Node node, DartType defaultValue) {
- return node != null ? analyze(node) : defaultValue;
- }
-
- /// If [inInitializer] is true, assignment should be interpreted as write to
- /// a field and not to a setter.
- DartType analyze(Node node, {bool inInitializer: false}) {
- if (node == null) {
- final String error = 'Unexpected node: null';
- if (lastSeenNode != null) {
- compiler.internalError(lastSeenNode, error);
- } else {
- compiler.internalError(elements.analyzedElement, error);
- }
- } else {
- lastSeenNode = node;
- }
- bool previouslyInitializer = analyzingInitializer;
- analyzingInitializer = inInitializer;
- DartType result = node.accept(this);
- analyzingInitializer = previouslyInitializer;
- if (result == null) {
- compiler.internalError(node, 'Type is null.');
- }
- return result;
- }
-
- void checkTypePromotion(Node node, TypePromotion typePromotion,
- {bool checkAccesses: false}) {
- VariableElement variable = typePromotion.variable;
- String variableName = variable.name;
- List<Node> potentialMutationsIn =
- elements.getPotentialMutationsIn(node, variable);
- if (!potentialMutationsIn.isEmpty) {
- typePromotion.addHint(typePromotion.node,
- MessageKind.POTENTIAL_MUTATION,
- {'variableName': variableName, 'shownType': typePromotion.type});
- for (Node mutation in potentialMutationsIn) {
- typePromotion.addInfo(mutation,
- MessageKind.POTENTIAL_MUTATION_HERE,
- {'variableName': variableName});
- }
- }
- List<Node> potentialMutationsInClosures =
- elements.getPotentialMutationsInClosure(variable);
- if (!potentialMutationsInClosures.isEmpty) {
- typePromotion.addHint(typePromotion.node,
- MessageKind.POTENTIAL_MUTATION_IN_CLOSURE,
- {'variableName': variableName, 'shownType': typePromotion.type});
- for (Node mutation in potentialMutationsInClosures) {
- typePromotion.addInfo(mutation,
- MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE,
- {'variableName': variableName});
- }
- }
- if (checkAccesses) {
- List<Node> accesses = elements.getAccessesByClosureIn(node, variable);
- List<Node> mutations = elements.getPotentialMutations(variable);
- if (!accesses.isEmpty && !mutations.isEmpty) {
- typePromotion.addHint(typePromotion.node,
- MessageKind.ACCESSED_IN_CLOSURE,
- {'variableName': variableName, 'shownType': typePromotion.type});
- for (Node access in accesses) {
- typePromotion.addInfo(access,
- MessageKind.ACCESSED_IN_CLOSURE_HERE,
- {'variableName': variableName});
- }
- for (Node mutation in mutations) {
- typePromotion.addInfo(mutation,
- MessageKind.POTENTIAL_MUTATION_HERE,
- {'variableName': variableName});
- }
- }
- }
- }
-
- /// Show type promotions from [left] and [right] in [node] given that the
- /// promoted variables are not potentially mutated in [right].
- void reshowTypePromotions(Node node, Node left, Node right) {
- for (TypePromotion typePromotion in getShownTypePromotionsFor(left)) {
- typePromotion = typePromotion.copy();
- checkTypePromotion(right, typePromotion);
- showTypePromotion(node, typePromotion);
- }
-
- for (TypePromotion typePromotion in getShownTypePromotionsFor(right)) {
- typePromotion = typePromotion.copy();
- checkTypePromotion(right, typePromotion);
- showTypePromotion(node, typePromotion);
- }
- }
-
- /// Analyze [node] in the context of the known types shown in [context].
- DartType analyzeInPromotedContext(Node context, Node node) {
- Link<TypePromotion> knownForNode = const Link<TypePromotion>();
- for (TypePromotion typePromotion in getShownTypePromotionsFor(context)) {
- typePromotion = typePromotion.copy();
- checkTypePromotion(node, typePromotion, checkAccesses: true);
- knownForNode = knownForNode.prepend(typePromotion);
- registerKnownTypePromotion(typePromotion);
- }
-
- final DartType type = analyze(node);
-
- while (!knownForNode.isEmpty) {
- unregisterKnownTypePromotion(knownForNode.head);
- knownForNode = knownForNode.tail;
- }
-
- return type;
- }
-
- /**
- * Check if a value of type [from] can be assigned to a variable, parameter or
- * return value of type [to]. If `isConst == true`, an error is emitted in
- * checked mode, otherwise a warning is issued.
- */
- bool checkAssignable(Spannable spannable, DartType from, DartType to,
- {bool isConst: false}) {
- if (!types.isAssignable(from, to)) {
- if (compiler.enableTypeAssertions && isConst) {
- compiler.reportError(spannable, MessageKind.NOT_ASSIGNABLE,
- {'fromType': from, 'toType': to});
- } else {
- reportTypeWarning(spannable, MessageKind.NOT_ASSIGNABLE,
- {'fromType': from, 'toType': to});
- }
- return false;
- }
- return true;
- }
-
- checkCondition(Expression condition) {
- checkAssignable(condition, analyze(condition), boolType);
- }
-
- void pushCascadeType(DartType type) {
- cascadeTypes = cascadeTypes.prepend(type);
- }
-
- DartType popCascadeType() {
- DartType type = cascadeTypes.head;
- cascadeTypes = cascadeTypes.tail;
- return type;
- }
-
- DartType visitBlock(Block node) {
- return analyze(node.statements);
- }
-
- DartType visitCascade(Cascade node) {
- analyze(node.expression);
- return popCascadeType();
- }
-
- DartType visitCascadeReceiver(CascadeReceiver node) {
- DartType type = analyze(node.expression);
- pushCascadeType(type);
- return type;
- }
-
- DartType visitDoWhile(DoWhile node) {
- analyze(node.body);
- checkCondition(node.condition);
- return const StatementType();
- }
-
- DartType visitExpressionStatement(ExpressionStatement node) {
- Expression expression = node.expression;
- analyze(expression);
- return const StatementType();
- }
-
- /** Dart Programming Language Specification: 11.5.1 For Loop */
- DartType visitFor(For node) {
- if (node.initializer != null) {
- analyze(node.initializer);
- }
- if (node.condition != null) {
- checkCondition(node.condition);
- }
- if (node.update != null) {
- analyze(node.update);
- }
- return analyze(node.body);
- }
-
- DartType visitFunctionDeclaration(FunctionDeclaration node) {
- analyze(node.function);
- return const StatementType();
- }
-
- DartType visitFunctionExpression(FunctionExpression node) {
- DartType type;
- DartType returnType;
- DartType previousType;
- final FunctionElement element = elements.getFunctionDefinition(node);
- assert(invariant(node, element != null,
- message: 'FunctionExpression with no element'));
- if (Elements.isUnresolved(element)) return const DynamicType();
- if (identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR) ||
- identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR_BODY)) {
- type = const DynamicType();
- returnType = const VoidType();
-
- element.functionSignature.forEachParameter((ParameterElement parameter) {
- if (parameter.isInitializingFormal) {
- InitializingFormalElement fieldParameter = parameter;
- checkAssignable(parameter, parameter.type,
- fieldParameter.fieldElement.computeType(compiler));
- }
- });
- if (node.initializers != null) {
- analyze(node.initializers, inInitializer: true);
- }
- } else {
- FunctionType functionType = element.computeType(compiler);
- returnType = functionType.returnType;
- type = functionType;
- }
- DartType previousReturnType = expectedReturnType;
- expectedReturnType = returnType;
- AsyncMarker previousAsyncMarker = currentAsyncMarker;
- currentAsyncMarker = element.asyncMarker;
- analyze(node.body);
- expectedReturnType = previousReturnType;
- currentAsyncMarker = previousAsyncMarker;
- return type;
- }
-
- DartType visitIdentifier(Identifier node) {
- if (node.isThis()) {
- return thisType;
- } else if (node.isSuper()) {
- return superType;
- } else {
- Element element = elements[node];
- assert(invariant(node, element != null,
- message: 'Missing element for identifier'));
- assert(invariant(node, element.isVariable ||
- element.isParameter ||
- element.isField,
- message: 'Unexpected context element ${element}'));
- return element.computeType(compiler);
- }
- }
-
- DartType visitIf(If node) {
- Expression condition = node.condition.expression;
- Statement thenPart = node.thenPart;
-
- checkCondition(node.condition);
- analyzeInPromotedContext(condition, thenPart);
- if (node.elsePart != null) {
- analyze(node.elsePart);
- }
- return const StatementType();
- }
-
- void checkPrivateAccess(Node node, Element element, String name) {
- if (name != null &&
- isPrivateName(name) &&
- element.library != currentLibrary) {
- reportTypeWarning(
- node,
- MessageKind.PRIVATE_ACCESS,
- {'name': name,
- 'libraryName': element.library.getLibraryOrScriptName()});
- }
-
- }
-
- ElementAccess lookupMember(Node node, DartType receiverType, String name,
- MemberKind memberKind, Element receiverElement,
- {bool lookupClassMember: false}) {
- if (receiverType.treatAsDynamic) {
- return const DynamicAccess();
- }
-
- Name memberName = new Name(name, currentLibrary,
- isSetter: memberKind == MemberKind.SETTER);
-
- // Compute the unaliased type of the first non type variable bound of
- // [type].
- DartType computeUnaliasedBound(DartType type) {
- DartType originalType = type;
- while (identical(type.kind, TypeKind.TYPE_VARIABLE)) {
- TypeVariableType variable = type;
- type = variable.element.bound;
- if (type == originalType) {
- type = compiler.objectClass.rawType;
- }
- }
- if (type.isMalformed) {
- return const DynamicType();
- }
- return type.unalias(compiler);
- }
-
- // Compute the interface type of [type]. For type variable it is the
- // interface type of the bound, for function types and typedefs it is the
- // `Function` type.
- InterfaceType computeInterfaceType(DartType type) {
- if (type.isFunctionType) {
- type = compiler.functionClass.rawType;
- }
- assert(invariant(node, type.isInterfaceType,
- message: "unexpected type kind ${type.kind}."));
- return type;
- }
-
- // Lookup the class or interface member [name] in [interface].
- MemberSignature lookupMemberSignature(Name name, InterfaceType interface) {
- MembersCreator.computeClassMembersByName(
- compiler, interface.element, name.text);
- return lookupClassMember || analyzingInitializer
- ? interface.lookupClassMember(name)
- : interface.lookupInterfaceMember(name);
- }
-
- // Compute the access of [name] on [type]. This function takes the special
- // 'call' method into account.
- ElementAccess getAccess(Name name,
- DartType unaliasedBound, InterfaceType interface) {
- MemberSignature member = lookupMemberSignature(memberName, interface);
- if (member != null) {
- return new MemberAccess(member);
- }
- if (name == const PublicName('call')) {
- if (unaliasedBound.isFunctionType) {
- // This is an access the implicit 'call' method of a function type.
- return new FunctionCallAccess(receiverElement, unaliasedBound);
- }
- if (types.isSubtype(interface, compiler.functionClass.rawType)) {
- // This is an access of the special 'call' method implicitly defined
- // on 'Function'. This method can be called with any arguments, which
- // we ensure by giving it the type 'dynamic'.
- return new FunctionCallAccess(null, const DynamicType());
- }
- }
- return null;
- }
-
- DartType unaliasedBound = computeUnaliasedBound(receiverType);
- if (unaliasedBound.treatAsDynamic) {
- return new DynamicAccess();
- }
- InterfaceType interface = computeInterfaceType(unaliasedBound);
- ElementAccess access = getAccess(memberName, unaliasedBound, interface);
- if (access != null) {
- return access;
- }
- if (receiverElement != null &&
- (receiverElement.isVariable || receiverElement.isParameter)) {
- Link<TypePromotion> typePromotions = typePromotionsMap[receiverElement];
- if (typePromotions != null) {
- while (!typePromotions.isEmpty) {
- TypePromotion typePromotion = typePromotions.head;
- if (!typePromotion.isValid) {
- DartType unaliasedBound = computeUnaliasedBound(typePromotion.type);
- if (!unaliasedBound.treatAsDynamic) {
- InterfaceType interface = computeInterfaceType(unaliasedBound);
- if (getAccess(memberName, unaliasedBound, interface) != null) {
- reportTypePromotionHint(typePromotion);
- }
- }
- }
- typePromotions = typePromotions.tail;
- }
- }
- }
- // We didn't find a member with the correct name. If this lookup is for a
- // super or redirecting initializer, the resolver has already emitted an
- // error message. If the target is a proxy, no warning needs to be emitted.
- // Otherwise, try to emit the most precise warning.
- if (!interface.element.isProxy && !analyzingInitializer) {
- bool foundPrivateMember = false;
- if (memberName.isPrivate) {
- void findPrivateMember(MemberSignature member) {
- if (memberName.isSimilarTo(member.name)) {
- PrivateName privateName = member.name;
- reportTypeWarning(
- node,
- MessageKind.PRIVATE_ACCESS,
- {'name': name,
- 'libraryName': privateName.library.getLibraryOrScriptName()});
- foundPrivateMember = true;
- }
- }
- // TODO(johnniwinther): Avoid computation of all class members.
- MembersCreator.computeAllClassMembers(compiler, interface.element);
- if (lookupClassMember) {
- interface.element.forEachClassMember(findPrivateMember);
- } else {
- interface.element.forEachInterfaceMember(findPrivateMember);
- }
-
- }
- if (!foundPrivateMember) {
- switch (memberKind) {
- case MemberKind.METHOD:
- reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND,
- {'className': receiverType.name, 'memberName': name});
- break;
- case MemberKind.OPERATOR:
- reportTypeWarning(node, MessageKind.OPERATOR_NOT_FOUND,
- {'className': receiverType.name, 'memberName': name});
- break;
- case MemberKind.GETTER:
- if (lookupMemberSignature(memberName.setter, interface) != null) {
- // A setter is present so warn explicitly about the missing
- // getter.
- reportTypeWarning(node, MessageKind.GETTER_NOT_FOUND,
- {'className': receiverType.name, 'memberName': name});
- } else {
- reportTypeWarning(node, MessageKind.MEMBER_NOT_FOUND,
- {'className': receiverType.name, 'memberName': name});
- }
- break;
- case MemberKind.SETTER:
- reportTypeWarning(node, MessageKind.SETTER_NOT_FOUND,
- {'className': receiverType.name, 'memberName': name});
- break;
- }
- }
- }
- return const DynamicAccess();
- }
-
- DartType lookupMemberType(Node node, DartType type, String name,
- MemberKind memberKind) {
- return lookupMember(node, type, name, memberKind, null)
- .computeType(compiler);
- }
-
- void analyzeArguments(Send send, Element element, DartType type,
- [LinkBuilder<DartType> argumentTypes]) {
- Link<Node> arguments = send.arguments;
- DartType unaliasedType = type.unalias(compiler);
- if (identical(unaliasedType.kind, TypeKind.FUNCTION)) {
- bool error = false;
- FunctionType funType = unaliasedType;
- Iterator<DartType> parameterTypes = funType.parameterTypes.iterator;
- Iterator<DartType> optionalParameterTypes =
- funType.optionalParameterTypes.iterator;
- while (!arguments.isEmpty) {
- Node argument = arguments.head;
- NamedArgument namedArgument = argument.asNamedArgument();
- if (namedArgument != null) {
- argument = namedArgument.expression;
- String argumentName = namedArgument.name.source;
- DartType namedParameterType =
- funType.getNamedParameterType(argumentName);
- if (namedParameterType == null) {
- error = true;
- // TODO(johnniwinther): Provide better information on the called
- // function.
- reportTypeWarning(argument, MessageKind.NAMED_ARGUMENT_NOT_FOUND,
- {'argumentName': argumentName});
-
- DartType argumentType = analyze(argument);
- if (argumentTypes != null) argumentTypes.addLast(argumentType);
- } else {
- DartType argumentType = analyze(argument);
- if (argumentTypes != null) argumentTypes.addLast(argumentType);
- if (!checkAssignable(argument, argumentType, namedParameterType)) {
- error = true;
- }
- }
- } else {
- if (!parameterTypes.moveNext()) {
- if (!optionalParameterTypes.moveNext()) {
- error = true;
- // TODO(johnniwinther): Provide better information on the
- // called function.
- reportTypeWarning(argument, MessageKind.ADDITIONAL_ARGUMENT);
-
- DartType argumentType = analyze(argument);
- if (argumentTypes != null) argumentTypes.addLast(argumentType);
- } else {
- DartType argumentType = analyze(argument);
- if (argumentTypes != null) argumentTypes.addLast(argumentType);
- if (!checkAssignable(argument,
- argumentType,
- optionalParameterTypes.current)) {
- error = true;
- }
- }
- } else {
- DartType argumentType = analyze(argument);
- if (argumentTypes != null) argumentTypes.addLast(argumentType);
- if (!checkAssignable(argument, argumentType,
- parameterTypes.current)) {
- error = true;
- }
- }
- }
- arguments = arguments.tail;
- }
- if (parameterTypes.moveNext()) {
- error = true;
- // TODO(johnniwinther): Provide better information on the called
- // function.
- reportTypeWarning(send, MessageKind.MISSING_ARGUMENT,
- {'argumentType': parameterTypes.current});
- }
- if (error) {
- // TODO(johnniwinther): Improve access to declaring element and handle
- // synthesized member signatures. Currently function typed instance
- // members provide no access to there own name.
- if (element == null) {
- element = type.element;
- } else if (type.element.isTypedef) {
- if (element != null) {
- reportTypeInfo(element,
- MessageKind.THIS_IS_THE_DECLARATION,
- {'name': element.name});
- }
- element = type.element;
- }
- reportTypeInfo(element, MessageKind.THIS_IS_THE_METHOD);
- }
- } else {
- while(!arguments.isEmpty) {
- DartType argumentType = analyze(arguments.head);
- if (argumentTypes != null) argumentTypes.addLast(argumentType);
- arguments = arguments.tail;
- }
- }
- }
-
- // Analyze the invocation [node] of [elementAccess].
- //
- // If provided [argumentTypes] is filled with the argument types during
- // analysis.
- DartType analyzeInvocation(Send node, ElementAccess elementAccess,
- [LinkBuilder<DartType> argumentTypes]) {
- DartType type = elementAccess.computeType(compiler);
- if (elementAccess.isCallable(compiler)) {
- analyzeArguments(node, elementAccess.element, type, argumentTypes);
- } else {
- reportTypeWarning(node, MessageKind.NOT_CALLABLE,
- {'elementName': elementAccess.element.name});
- analyzeArguments(node, elementAccess.element, const DynamicType(),
- argumentTypes);
- }
- type = type.unalias(compiler);
- if (identical(type.kind, TypeKind.FUNCTION)) {
- FunctionType funType = type;
- return funType.returnType;
- } else {
- return const DynamicType();
- }
- }
-
- /**
- * Computes the [ElementAccess] for [name] on the [node] possibly using the
- * [element] provided for [node] by the resolver.
- */
- ElementAccess computeAccess(Send node, String name, Element element,
- MemberKind memberKind,
- {bool lookupClassMember: false}) {
- if (element != null && element.isErroneous) {
- // An error has already been reported for this node.
- return const DynamicAccess();
- }
- if (node.receiver != null) {
- Element receiverElement = elements[node.receiver];
- if (receiverElement != null) {
- if (receiverElement.isPrefix) {
- assert(invariant(node, element != null,
- message: 'Prefixed node has no element.'));
- return computeResolvedAccess(node, name, element, memberKind);
- }
- }
- // e.foo() for some expression e.
- DartType receiverType = analyze(node.receiver);
- if (receiverType.treatAsDynamic || receiverType.isVoid) {
- return const DynamicAccess();
- }
- TypeKind receiverKind = receiverType.kind;
- return lookupMember(node, receiverType, name, memberKind,
- elements[node.receiver],
- lookupClassMember: lookupClassMember ||
- element != null && element.isStatic);
- } else {
- return computeResolvedAccess(node, name, element, memberKind);
- }
- }
-
- /**
- * Computes the [ElementAccess] for [name] on the [node] using the [element]
- * provided for [node] by the resolver.
- */
- ElementAccess computeResolvedAccess(Send node, String name,
- Element element, MemberKind memberKind) {
- if (element == null) {
- // foo() where foo is unresolved.
- return lookupMember(node, thisType, name, memberKind, null);
- } else if (element.isErroneous) {
- // foo() where foo is erroneous.
- return const DynamicAccess();
- } else if (element.impliesType) {
- // The literal `Foo` where Foo is a class, a typedef, or a type variable.
- if (elements.isTypeLiteral(node)) {
- return new TypeLiteralAccess(elements.getTypeLiteralType(node));
- }
- return createResolvedAccess(node, name, element);
- } else if (element.isClassMember) {
- // foo() where foo is a member.
- return lookupMember(node, thisType, name, memberKind, null,
- lookupClassMember: element.isStatic);
- } else if (element.isFunction) {
- // foo() where foo is a method in the same class.
- return createResolvedAccess(node, name, element);
- } else if (element.isVariable ||
- element.isParameter ||
- element.isField) {
- // foo() where foo is a field in the same class.
- return createResolvedAccess(node, name, element);
- } else if (element.isGetter || element.isSetter) {
- return createResolvedAccess(node, name, element);
- } else {
- compiler.internalError(element,
- 'Unexpected element kind ${element.kind}.');
- return null;
- }
- }
-
- ElementAccess createResolvedAccess(Send node, String name,
- Element element) {
- checkPrivateAccess(node, element, name);
- return createPromotedAccess(element);
- }
-
- ElementAccess createPromotedAccess(Element element) {
- if (element.isVariable || element.isParameter) {
- TypePromotion typePromotion = getKnownTypePromotion(element);
- if (typePromotion != null) {
- return new PromotedAccess(element, typePromotion.type);
- }
- }
- return new ResolvedAccess(element);
- }
-
- /**
- * Computes the type of the access of [name] on the [node] possibly using the
- * [element] provided for [node] by the resolver.
- */
- DartType computeAccessType(Send node, String name, Element element,
- MemberKind memberKind,
- {bool lookupClassMember: false}) {
- DartType type =
- computeAccess(node, name, element, memberKind,
- lookupClassMember: lookupClassMember).computeType(compiler);
- if (type == null) {
- compiler.internalError(node, 'Type is null on access of $name on $node.');
- }
- return type;
- }
-
- /// Compute a version of [shownType] that is more specific that [knownType].
- /// This is used to provided better hints when trying to promote a supertype
- /// to a raw subtype. For instance trying to promote `Iterable<int>` to `List`
- /// we suggest the use of `List<int>`, which would make promotion valid.
- DartType computeMoreSpecificType(DartType shownType,
- DartType knownType) {
- if (knownType.isInterfaceType &&
- shownType.isInterfaceType &&
- types.isSubtype(shownType.asRaw(), knownType)) {
- // For the comments in the block, assume the hierarchy:
- // class A<T, V> {}
- // class B<S, U> extends A<S, int> {}
- // and a promotion from a [knownType] of `A<double, int>` to a
- // [shownType] of `B`.
- InterfaceType knownInterfaceType = knownType;
- ClassElement shownClass = shownType.element;
-
- // Compute `B<double, dynamic>` as the subtype of `A<double, int>` using
- // the relation between `A<S, int>` and `A<double, int>`.
- MoreSpecificSubtypeVisitor visitor =
- new MoreSpecificSubtypeVisitor(compiler);
- InterfaceType shownTypeGeneric = visitor.computeMoreSpecific(
- shownClass, knownInterfaceType);
-
- if (shownTypeGeneric != null &&
- types.isMoreSpecific(shownTypeGeneric, knownType)) {
- // This should be the case but we double-check.
- // TODO(johnniwinther): Ensure that we don't suggest malbounded types.
- return shownTypeGeneric;
- }
- }
- return null;
-
- }
-
- DartType visitSend(Send node) {
- if (elements.isAssert(node)) {
- return analyzeInvocation(node, const AssertAccess());
- }
-
- Element element = elements[node];
-
- if (element != null && element.isConstructor) {
- DartType receiverType;
- if (node.receiver != null) {
- receiverType = analyze(node.receiver);
- } else if (node.selector.isSuper()) {
- // TODO(johnniwinther): Lookup super-member in class members.
- receiverType = superType;
- } else {
- assert(node.selector.isThis());
- receiverType = thisType;
- }
- DartType constructorType = computeConstructorType(element, receiverType);
- analyzeArguments(node, element, constructorType);
- return const DynamicType();
- }
-
- if (Elements.isClosureSend(node, element)) {
- if (element != null) {
- // foo() where foo is a local or a parameter.
- return analyzeInvocation(node, createPromotedAccess(element));
- } else {
- // exp() where exp is some complex expression like (o) or foo().
- DartType type = analyze(node.selector);
- return analyzeInvocation(node, new TypeAccess(type));
- }
- }
-
- Identifier selector = node.selector.asIdentifier();
- String name = selector.source;
-
- if (node.isOperator && identical(name, 'is')) {
- analyze(node.receiver);
- if (!node.isIsNotCheck) {
- Element variable = elements[node.receiver];
- if (variable == null) {
- // Look for the variable element within parenthesized expressions.
- ParenthesizedExpression parentheses =
- node.receiver.asParenthesizedExpression();
- while (parentheses != null) {
- variable = elements[parentheses.expression];
- if (variable != null) break;
- parentheses = parentheses.expression.asParenthesizedExpression();
- }
- }
-
- if (variable != null &&
- (variable.isVariable || variable.isParameter)) {
- DartType knownType = getKnownType(variable);
- if (!knownType.isDynamic) {
- DartType shownType = elements.getType(node.arguments.head);
- TypePromotion typePromotion =
- new TypePromotion(node, variable, shownType);
- if (!types.isMoreSpecific(shownType, knownType)) {
- String variableName = variable.name;
- if (!types.isSubtype(shownType, knownType)) {
- typePromotion.addHint(node,
- MessageKind.NOT_MORE_SPECIFIC_SUBTYPE,
- {'variableName': variableName,
- 'shownType': shownType,
- 'knownType': knownType});
- } else {
- DartType shownTypeSuggestion =
- computeMoreSpecificType(shownType, knownType);
- if (shownTypeSuggestion != null) {
- typePromotion.addHint(node,
- MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
- {'variableName': variableName,
- 'shownType': shownType,
- 'shownTypeSuggestion': shownTypeSuggestion,
- 'knownType': knownType});
- } else {
- typePromotion.addHint(node,
- MessageKind.NOT_MORE_SPECIFIC,
- {'variableName': variableName,
- 'shownType': shownType,
- 'knownType': knownType});
- }
- }
- }
- showTypePromotion(node, typePromotion);
- }
- }
- }
- return boolType;
- } if (node.isOperator && identical(name, 'as')) {
- analyze(node.receiver);
- return elements.getType(node.arguments.head);
- } else if (node.isOperator) {
- final Node receiver = node.receiver;
- final DartType receiverType = analyze(receiver);
- if (identical(name, '==') || identical(name, '!=')
- // TODO(johnniwinther): Remove these.
- || identical(name, '===') || identical(name, '!==')) {
- // Analyze argument.
- analyze(node.arguments.head);
- return boolType;
- } else if (identical(name, '||')) {
- checkAssignable(receiver, receiverType, boolType);
- final Node argument = node.arguments.head;
- final DartType argumentType = analyze(argument);
- checkAssignable(argument, argumentType, boolType);
- return boolType;
- } else if (identical(name, '&&')) {
- checkAssignable(receiver, receiverType, boolType);
- final Node argument = node.arguments.head;
-
- final DartType argumentType =
- analyzeInPromotedContext(receiver, argument);
-
- reshowTypePromotions(node, receiver, argument);
-
- checkAssignable(argument, argumentType, boolType);
- return boolType;
- } else if (identical(name, '!')) {
- checkAssignable(receiver, receiverType, boolType);
- return boolType;
- } else if (identical(name, '?')) {
- return boolType;
- }
- String operatorName = selector.source;
- if (identical(name, '-') && node.arguments.isEmpty) {
- operatorName = 'unary-';
- }
- assert(invariant(node,
- identical(name, '+') || identical(name, '=') ||
- identical(name, '-') || identical(name, '*') ||
- identical(name, '/') || identical(name, '%') ||
- identical(name, '~/') || identical(name, '|') ||
- identical(name, '&') || identical(name, '^') ||
- identical(name, '~')|| identical(name, '<<') ||
- identical(name, '>>') ||
- identical(name, '<') || identical(name, '>') ||
- identical(name, '<=') || identical(name, '>=') ||
- identical(name, '[]'),
- message: 'Unexpected operator $name'));
-
- // TODO(karlklose): handle `void` in expression context by calling
- // [analyzeNonVoid] instead of [analyze].
- ElementAccess access = receiverType.isVoid ? const DynamicAccess()
- : lookupMember(node, receiverType, operatorName,
- MemberKind.OPERATOR, null);
- LinkBuilder<DartType> argumentTypesBuilder = new LinkBuilder<DartType>();
- DartType resultType =
- analyzeInvocation(node, access, argumentTypesBuilder);
- if (identical(receiverType.element, compiler.intClass)) {
- if (identical(name, '+') ||
- identical(operatorName, '-') ||
- identical(name, '*') ||
- identical(name, '%')) {
- DartType argumentType = argumentTypesBuilder.toLink().head;
- if (identical(argumentType.element, compiler.intClass)) {
- return intType;
- } else if (identical(argumentType.element, compiler.doubleClass)) {
- return doubleType;
- }
- }
- }
- return resultType;
- } else if (node.isPropertyAccess) {
- ElementAccess access =
- computeAccess(node, selector.source, element, MemberKind.GETTER);
- return access.computeType(compiler);
- } else if (node.isFunctionObjectInvocation) {
- return unhandledExpression();
- } else {
- ElementAccess access =
- computeAccess(node, selector.source, element, MemberKind.METHOD);
- return analyzeInvocation(node, access);
- }
- }
-
- /// Returns the first type in the list or [:dynamic:] if the list is empty.
- DartType firstType(List<DartType> list) {
- return list.isEmpty ? const DynamicType() : list.first;
- }
-
- /**
- * Returns the second type in the list or [:dynamic:] if the list is too
- * short.
- */
- DartType secondType(List<DartType> list) {
- return list.length < 2 ? const DynamicType() : list[1];
- }
-
- /**
- * Checks [: target o= value :] for some operator o, and returns the type
- * of the result. This method also handles increment/decrement expressions
- * like [: target++ :].
- */
- DartType checkAssignmentOperator(SendSet node,
- String operatorName,
- Node valueNode,
- DartType value) {
- assert(invariant(node, !node.isIndex));
- Element setterElement = elements[node];
- Element getterElement = elements[node.selector];
- Identifier selector = node.selector;
- DartType getter = computeAccessType(
- node, selector.source, getterElement, MemberKind.GETTER);
- DartType setter = computeAccessType(
- node, selector.source, setterElement, MemberKind.SETTER);
- // [operator] is the type of operator+ or operator- on [target].
- DartType operator =
- lookupMemberType(node, getter, operatorName, MemberKind.OPERATOR);
- if (operator is FunctionType) {
- FunctionType operatorType = operator;
- // [result] is the type of target o value.
- DartType result = operatorType.returnType;
- DartType operatorArgument = firstType(operatorType.parameterTypes);
- // Check target o value.
- bool validValue = checkAssignable(valueNode, value, operatorArgument);
- if (validValue || !(node.isPrefix || node.isPostfix)) {
- // Check target = result.
- checkAssignable(node.assignmentOperator, result, setter);
- }
- return node.isPostfix ? getter : result;
- }
- return const DynamicType();
- }
-
- /**
- * Checks [: base[key] o= value :] for some operator o, and returns the type
- * of the result. This method also handles increment/decrement expressions
- * like [: base[key]++ :].
- */
- DartType checkIndexAssignmentOperator(SendSet node,
- String operatorName,
- Node valueNode,
- DartType value) {
- assert(invariant(node, node.isIndex));
- final DartType base = analyze(node.receiver);
- final Node keyNode = node.arguments.head;
- final DartType key = analyze(keyNode);
-
- // [indexGet] is the type of operator[] on [base].
- DartType indexGet = lookupMemberType(
- node, base, '[]', MemberKind.OPERATOR);
- if (indexGet is FunctionType) {
- FunctionType indexGetType = indexGet;
- DartType indexGetKey = firstType(indexGetType.parameterTypes);
- // Check base[key].
- bool validKey = checkAssignable(keyNode, key, indexGetKey);
-
- // [element] is the type of base[key].
- DartType element = indexGetType.returnType;
- // [operator] is the type of operator o on [element].
- DartType operator = lookupMemberType(
- node, element, operatorName, MemberKind.OPERATOR);
- if (operator is FunctionType) {
- FunctionType operatorType = operator;
-
- // Check base[key] o value.
- DartType operatorArgument = firstType(operatorType.parameterTypes);
- bool validValue = checkAssignable(valueNode, value, operatorArgument);
-
- // [result] is the type of base[key] o value.
- DartType result = operatorType.returnType;
-
- // [indexSet] is the type of operator[]= on [base].
- DartType indexSet = lookupMemberType(
- node, base, '[]=', MemberKind.OPERATOR);
- if (indexSet is FunctionType) {
- FunctionType indexSetType = indexSet;
- DartType indexSetKey = firstType(indexSetType.parameterTypes);
- DartType indexSetValue = secondType(indexSetType.parameterTypes);
-
- if (validKey || indexGetKey != indexSetKey) {
- // Only check base[key] on []= if base[key] was valid for [] or
- // if the key types differ.
- checkAssignable(keyNode, key, indexSetKey);
- }
- // Check base[key] = result
- if (validValue || !(node.isPrefix || node.isPostfix)) {
- checkAssignable(node.assignmentOperator, result, indexSetValue);
- }
- }
- return node.isPostfix ? element : result;
- }
- }
- return const DynamicType();
- }
-
- visitSendSet(SendSet node) {
- Element element = elements[node];
- Identifier selector = node.selector;
- final name = node.assignmentOperator.source;
- if (identical(name, '=')) {
- // e1 = value
- if (node.isIndex) {
- // base[key] = value
- final DartType base = analyze(node.receiver);
- final Node keyNode = node.arguments.head;
- final DartType key = analyze(keyNode);
- final Node valueNode = node.arguments.tail.head;
- final DartType value = analyze(valueNode);
- DartType indexSet = lookupMemberType(
- node, base, '[]=', MemberKind.OPERATOR);
- if (indexSet is FunctionType) {
- FunctionType indexSetType = indexSet;
- DartType indexSetKey = firstType(indexSetType.parameterTypes);
- checkAssignable(keyNode, key, indexSetKey);
- DartType indexSetValue = secondType(indexSetType.parameterTypes);
- checkAssignable(node.assignmentOperator, value, indexSetValue);
- }
- return value;
- } else {
- // target = value
- DartType target;
- if (analyzingInitializer) {
- // Field declaration `Foo target = value;` or initializer
- // `this.target = value`. Lookup the getter `target` in the class
- // members.
- target = computeAccessType(node, selector.source, element,
- MemberKind.GETTER, lookupClassMember: true);
- } else {
- // Normal assignment `target = value`.
- target = computeAccessType(
- node, selector.source, element, MemberKind.SETTER);
- }
- final Node valueNode = node.arguments.head;
- final DartType value = analyze(valueNode);
- checkAssignable(node.assignmentOperator, value, target);
- return value;
- }
- } else if (identical(name, '++') || identical(name, '--')) {
- // e++ or e--
- String operatorName = identical(name, '++') ? '+' : '-';
- if (node.isIndex) {
- // base[key]++, base[key]--, ++base[key], or --base[key]
- return checkIndexAssignmentOperator(
- node, operatorName, node.assignmentOperator, intType);
- } else {
- // target++, target--, ++target, or --target
- return checkAssignmentOperator(
- node, operatorName, node.assignmentOperator, intType);
- }
- } else {
- // e1 o= e2 for some operator o.
- String operatorName;
- switch (name) {
- case '+=': operatorName = '+'; break;
- case '-=': operatorName = '-'; break;
- case '*=': operatorName = '*'; break;
- case '/=': operatorName = '/'; break;
- case '%=': operatorName = '%'; break;
- case '~/=': operatorName = '~/'; break;
- case '&=': operatorName = '&'; break;
- case '|=': operatorName = '|'; break;
- case '^=': operatorName = '^'; break;
- case '<<=': operatorName = '<<'; break;
- case '>>=': operatorName = '>>'; break;
- default:
- compiler.internalError(node, 'Unexpected assignment operator $name.');
- }
- if (node.isIndex) {
- // base[key] o= value for some operator o.
- final Node valueNode = node.arguments.tail.head;
- final DartType value = analyze(valueNode);
- return checkIndexAssignmentOperator(
- node, operatorName, valueNode, value);
- } else {
- // target o= value for some operator o.
- final Node valueNode = node.arguments.head;
- final DartType value = analyze(valueNode);
- return checkAssignmentOperator(node, operatorName, valueNode, value);
- }
- }
- }
-
- DartType visitLiteralInt(LiteralInt node) {
- return intType;
- }
-
- DartType visitLiteralDouble(LiteralDouble node) {
- return doubleType;
- }
-
- DartType visitLiteralBool(LiteralBool node) {
- return boolType;
- }
-
- DartType visitLiteralString(LiteralString node) {
- return stringType;
- }
-
- DartType visitStringJuxtaposition(StringJuxtaposition node) {
- analyze(node.first);
- analyze(node.second);
- return stringType;
- }
-
- DartType visitLiteralNull(LiteralNull node) {
- return const DynamicType();
- }
-
- DartType visitLiteralSymbol(LiteralSymbol node) {
- return compiler.symbolClass.rawType;
- }
-
- DartType computeConstructorType(Element constructor, DartType type) {
- if (Elements.isUnresolved(constructor)) return const DynamicType();
- DartType constructorType = constructor.computeType(compiler);
- if (identical(type.kind, TypeKind.INTERFACE)) {
- if (constructor.isSynthesized) {
- // TODO(johnniwinther): Remove this when synthesized constructors handle
- // type variables correctly.
- InterfaceType interfaceType = type;
- ClassElement receiverElement = interfaceType.element;
- while (receiverElement.isMixinApplication) {
- receiverElement = receiverElement.supertype.element;
- }
- constructorType = constructorType.substByContext(
- interfaceType.asInstanceOf(receiverElement));
- } else {
- constructorType = constructorType.substByContext(type);
- }
- }
- return constructorType;
- }
-
- DartType visitNewExpression(NewExpression node) {
- Element element = elements[node.send];
- if (Elements.isUnresolved(element)) return const DynamicType();
-
- checkPrivateAccess(node, element, element.name);
-
- DartType newType = elements.getType(node);
- DartType constructorType = computeConstructorType(element, newType);
- analyzeArguments(node.send, element, constructorType);
- return newType;
- }
-
- DartType visitLiteralList(LiteralList node) {
- InterfaceType listType = elements.getType(node);
- DartType listElementType = firstType(listType.typeArguments);
- for (Link<Node> link = node.elements.nodes;
- !link.isEmpty;
- link = link.tail) {
- Node element = link.head;
- DartType elementType = analyze(element);
- checkAssignable(element, elementType, listElementType,
- isConst: node.isConst);
- }
- return listType;
- }
-
- DartType visitNodeList(NodeList node) {
- for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
- analyze(link.head, inInitializer: analyzingInitializer);
- }
- return const StatementType();
- }
-
- DartType visitRedirectingFactoryBody(RedirectingFactoryBody node) {
- // TODO(lrn): Typecheck the body. It must refer to the constructor
- // of a subtype.
- return const StatementType();
- }
-
- DartType visitRethrow(Rethrow node) {
- return const StatementType();
- }
-
- /** Dart Programming Language Specification: 11.10 Return */
- DartType visitReturn(Return node) {
- if (identical(node.beginToken.stringValue, 'native')) {
- return const StatementType();
- }
-
- final expression = node.expression;
- final isVoidFunction = expectedReturnType.isVoid;
-
- // Executing a return statement return e; [...] It is a static type warning
- // if the type of e may not be assigned to the declared return type of the
- // immediately enclosing function.
- if (expression != null) {
- final expressionType = analyze(expression);
- Element element = elements.analyzedElement;
- if (element != null && element.isGenerativeConstructor) {
- // The resolver already emitted an error for this expression.
- } else if (isVoidFunction
- && !types.isAssignable(expressionType, const VoidType())) {
- reportTypeWarning(expression, MessageKind.RETURN_VALUE_IN_VOID);
- } else {
- checkAssignable(expression, expressionType, expectedReturnType);
- }
-
- // Let f be the function immediately enclosing a return statement of the
- // form 'return;' It is a static warning if both of the following conditions
- // hold:
- // - f is not a generative constructor.
- // - The return type of f may not be assigned to void.
- } else if (!types.isAssignable(expectedReturnType, const VoidType())) {
- reportTypeWarning(node, MessageKind.RETURN_NOTHING,
- {'returnType': expectedReturnType});
- }
- return const StatementType();
- }
-
- DartType visitThrow(Throw node) {
- // TODO(johnniwinther): Handle reachability.
- analyze(node.expression);
- return const DynamicType();
- }
-
- DartType visitAwait(Await node) {
- DartType expressionType = analyze(node.expression);
- DartType resultType = expressionType;
- if (expressionType is InterfaceType) {
- InterfaceType futureType =
- expressionType.asInstanceOf(compiler.futureClass);
- if (futureType != null) {
- resultType = futureType.typeArguments.first;
- }
- }
- return resultType;
- }
-
- DartType visitYield(Yield node) {
- DartType resultType = analyze(node.expression);
- if (!node.hasStar) {
- if (currentAsyncMarker.isAsync) {
- resultType =
- compiler.streamClass.thisType.createInstantiation(
- <DartType>[resultType]);
- } else {
- resultType =
- compiler.iterableClass.thisType.createInstantiation(
- <DartType>[resultType]);
- }
- }
- checkAssignable(node, resultType, expectedReturnType);
- return const StatementType();
- }
-
- DartType visitTypeAnnotation(TypeAnnotation node) {
- return elements.getType(node);
- }
-
- DartType visitVariableDefinitions(VariableDefinitions node) {
- DartType type = analyzeWithDefault(node.type, const DynamicType());
- if (type.isVoid) {
- reportTypeWarning(node.type, MessageKind.VOID_VARIABLE);
- type = const DynamicType();
- }
- for (Link<Node> link = node.definitions.nodes; !link.isEmpty;
- link = link.tail) {
- Node definition = link.head;
- invariant(definition, definition is Identifier || definition is SendSet,
- message: 'expected identifier or initialization');
- if (definition is SendSet) {
- SendSet initialization = definition;
- DartType initializer = analyzeNonVoid(initialization.arguments.head);
- checkAssignable(initialization.assignmentOperator, initializer, type);
- }
- }
- return const StatementType();
- }
-
- DartType visitWhile(While node) {
- checkCondition(node.condition);
- analyze(node.body);
- Expression cond = node.condition.asParenthesizedExpression().expression;
- return const StatementType();
- }
-
- DartType visitParenthesizedExpression(ParenthesizedExpression node) {
- Expression expression = node.expression;
- DartType type = analyze(expression);
- for (TypePromotion typePromotion in getShownTypePromotionsFor(expression)) {
- showTypePromotion(node, typePromotion);
- }
- return type;
- }
-
- DartType visitConditional(Conditional node) {
- Expression condition = node.condition;
- Expression thenExpression = node.thenExpression;
-
- checkCondition(condition);
-
- DartType thenType = analyzeInPromotedContext(condition, thenExpression);
-
- DartType elseType = analyze(node.elseExpression);
- return compiler.types.computeLeastUpperBound(thenType, elseType);
- }
-
- visitStringInterpolation(StringInterpolation node) {
- node.visitChildren(this);
- return stringType;
- }
-
- visitStringInterpolationPart(StringInterpolationPart node) {
- node.visitChildren(this);
- return stringType;
- }
-
- visitEmptyStatement(EmptyStatement node) {
- return const StatementType();
- }
-
- visitBreakStatement(BreakStatement node) {
- return const StatementType();
- }
-
- visitContinueStatement(ContinueStatement node) {
- return const StatementType();
- }
-
- visitForIn(ForIn node) {
- analyze(node.expression);
- analyze(node.body);
- return const StatementType();
- }
-
- visitLabeledStatement(LabeledStatement node) {
- return analyze(node.statement);
- }
-
- visitLiteralMap(LiteralMap node) {
- InterfaceType mapType = elements.getType(node);
- DartType mapKeyType = firstType(mapType.typeArguments);
- DartType mapValueType = secondType(mapType.typeArguments);
- bool isConst = node.isConst;
- for (Link<Node> link = node.entries.nodes;
- !link.isEmpty;
- link = link.tail) {
- LiteralMapEntry entry = link.head;
- DartType keyType = analyze(entry.key);
- checkAssignable(entry.key, keyType, mapKeyType, isConst: isConst);
- DartType valueType = analyze(entry.value);
- checkAssignable(entry.value, valueType, mapValueType, isConst: isConst);
- }
- return mapType;
- }
-
- visitNamedArgument(NamedArgument node) {
- // Named arguments are visited as part of analyzing invocations of
- // unresolved methods. For instance [: foo(a: 42); :] where 'foo' is neither
- // found in the enclosing scope nor through lookup on 'this' or
- // [: x.foo(b: 42); :] where 'foo' cannot be not found through lookup on
- // the static type of 'x'.
- return analyze(node.expression);
- }
-
- visitSwitchStatement(SwitchStatement node) {
- // TODO(johnniwinther): Handle reachability based on reachability of
- // switch cases.
-
- DartType expressionType = analyze(node.expression);
-
- // Check that all the case expressions are assignable to the expression.
- for (SwitchCase switchCase in node.cases) {
- for (Node labelOrCase in switchCase.labelsAndCases) {
- CaseMatch caseMatch = labelOrCase.asCaseMatch();
- if (caseMatch == null) continue;
-
- DartType caseType = analyze(caseMatch.expression);
- checkAssignable(caseMatch, expressionType, caseType);
- }
-
- analyze(switchCase);
- }
-
- return const StatementType();
- }
-
- visitSwitchCase(SwitchCase node) {
- return analyze(node.statements);
- }
-
- visitTryStatement(TryStatement node) {
- // TODO(johnniwinther): Use reachability information of try-block,
- // catch-blocks and finally-block to compute the whether the try statement
- // is returning.
- analyze(node.tryBlock);
- for (CatchBlock catchBlock in node.catchBlocks) {
- analyze(catchBlock);
- }
- analyzeWithDefault(node.finallyBlock, null);
- return const StatementType();
- }
-
- visitCatchBlock(CatchBlock node) {
- return analyze(node.block);
- }
-
- visitTypedef(Typedef node) {
- // Do not typecheck [Typedef] nodes.
- }
-
- visitNode(Node node) {
- compiler.internalError(node,
- 'Unexpected node ${node.getObjectDescription()} in the type checker.');
- }
-}

Powered by Google App Engine
This is Rietveld 408576698