Skip to content

Commit

Permalink
Type check field initializers in the correct context.
Browse files Browse the repository at this point in the history
Closes #27104

R=sigmund@google.com

Review URL: https://codereview.chromium.org/2250433007 .
  • Loading branch information
johnniwinther committed Aug 19, 2016
1 parent a730f03 commit d4d5a48
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 4 deletions.
29 changes: 25 additions & 4 deletions pkg/compiler/lib/src/typechecker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@ class TypeCheckerTask extends CompilerTask {
compiler, resolvedAst.elements, compiler.types);
if (element.isField) {
visitor.analyzingInitializer = true;
DartType type =
visitor.analyzeVariableTypeAnnotation(resolvedAst.node);
visitor.analyzeVariableInitializer(element, type, resolvedAst.body);
} else {
resolvedAst.node.accept(visitor);
}
resolvedAst.node.accept(visitor);
});
});
}
Expand Down Expand Up @@ -1641,6 +1645,8 @@ class TypeCheckerVisitor extends Visitor<DartType> {
checkPrivateAccess(node, element, element.name);

DartType newType = elements.getType(node);
assert(invariant(node, newType != null,
message: "No new type registered in $elements."));
DartType constructorType = computeConstructorType(element, newType);
analyzeArguments(node.send, element, constructorType);
return newType;
Expand Down Expand Up @@ -1758,12 +1764,25 @@ class TypeCheckerVisitor extends Visitor<DartType> {
return elements.getType(node);
}

DartType visitVariableDefinitions(VariableDefinitions node) {
DartType analyzeVariableTypeAnnotation(VariableDefinitions node) {
DartType type = analyzeWithDefault(node.type, const DynamicType());
if (type.isVoid) {
reportTypeWarning(node.type, MessageKind.VOID_VARIABLE);
type = const DynamicType();
}
return type;
}

void analyzeVariableInitializer(
Spannable spannable, DartType declaredType, Node initializer) {
if (initializer == null) return;

DartType expressionType = analyzeNonVoid(initializer);
checkAssignable(spannable, expressionType, declaredType);
}

DartType visitVariableDefinitions(VariableDefinitions node) {
DartType type = analyzeVariableTypeAnnotation(node);
for (Link<Node> link = node.definitions.nodes;
!link.isEmpty;
link = link.tail) {
Expand All @@ -1772,8 +1791,10 @@ class TypeCheckerVisitor extends Visitor<DartType> {
message: 'expected identifier or initialization');
if (definition is SendSet) {
SendSet initialization = definition;
DartType initializer = analyzeNonVoid(initialization.arguments.head);
checkAssignable(initialization.assignmentOperator, initializer, type);
analyzeVariableInitializer(
initialization.assignmentOperator,
type,
initialization.arguments.head);
// TODO(sigmund): explore inferring a type for `var` using the RHS (like
// DDC does), for example:
// if (node.type == null && node.modifiers.isVar &&
Expand Down
16 changes: 16 additions & 0 deletions tests/language/typecheck_multifield_declaration_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) 2016, 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.

/// Checks that we can correctly typecheck multi-variable declarations on fields
/// and top-levels. This is also a regression test for Issue 27401.
class A {}

A a = new A(), b = new A();

class B {
A a = new A(), b = new A();
}

main() => [a, b, new B().a, new B().b];

0 comments on commit d4d5a48

Please sign in to comment.