diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart index ac087dd97d7..3f7d25c02a2 100644 --- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart +++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart @@ -322,4 +322,10 @@ class KernelTypeGraphBuilder extends ir.Visitor { receiverType, _analyzedMember, arguments, _sideEffects, inLoop: inLoop, isConditional: false); } + + @override + TypeInformation visitLet(ir.Let node) { + visit(node.variable); + return visit(node.body); + } } diff --git a/tests/compiler/dart2js/equivalence/id_equivalence.dart b/tests/compiler/dart2js/equivalence/id_equivalence.dart index a3b0fac317c..2dc5ffa57d7 100644 --- a/tests/compiler/dart2js/equivalence/id_equivalence.dart +++ b/tests/compiler/dart2js/equivalence/id_equivalence.dart @@ -345,7 +345,9 @@ abstract class AstDataExtractor extends ast.Visitor with DataRegistry { computeForNode(node, createUpdateId(position)); } break; + case SendStructureKind.PREFIX: case SendStructureKind.POSTFIX: + case SendStructureKind.COMPOUND: computeForNode(node, createAccessId(node.selector)); computeForNode(node, createInvokeId(node.assignmentOperator)); computeForNode(node, createUpdateId(node.selector)); @@ -425,17 +427,20 @@ abstract class IrDataExtractor extends ir.Visitor with DataRegistry { } NodeId computeDefaultNodeId(ir.TreeNode node) { - assert(node.fileOffset != ir.TreeNode.noOffset); + assert(node.fileOffset != ir.TreeNode.noOffset, + "No fileOffset on $node (${node.runtimeType})"); return new NodeId(node.fileOffset, IdKind.node); } NodeId createInvokeId(ir.TreeNode node) { - assert(node.fileOffset != ir.TreeNode.noOffset); + assert(node.fileOffset != ir.TreeNode.noOffset, + "No fileOffset on ${node} (${node.runtimeType})"); return new NodeId(node.fileOffset, IdKind.invoke); } NodeId createUpdateId(ir.TreeNode node) { - assert(node.fileOffset != ir.TreeNode.noOffset); + assert(node.fileOffset != ir.TreeNode.noOffset, + "No fileOffset on ${node} (${node.runtimeType})"); return new NodeId(node.fileOffset, IdKind.update); } @@ -469,7 +474,8 @@ abstract class IrDataExtractor extends ir.Visitor with DataRegistry { } visitVariableDeclaration(ir.VariableDeclaration node) { - if (node.parent is! ir.FunctionDeclaration) { + if (node.name != null && node.parent is! ir.FunctionDeclaration) { + // Skip synthetic variables and function declaration variables. computeForNode(node, computeDefaultNodeId(node)); } super.visitVariableDeclaration(node); @@ -486,7 +492,10 @@ abstract class IrDataExtractor extends ir.Visitor with DataRegistry { } visitVariableGet(ir.VariableGet node) { - computeForNode(node, computeDefaultNodeId(node)); + if (node.variable.name != null) { + // Skip use of synthetic variables. + computeForNode(node, computeDefaultNodeId(node)); + } super.visitVariableGet(node); } @@ -496,7 +505,10 @@ abstract class IrDataExtractor extends ir.Visitor with DataRegistry { } visitVariableSet(ir.VariableSet node) { - computeForNode(node, createUpdateId(node)); + if (node.variable.name != null) { + // Skip use of synthetic variables. + computeForNode(node, createUpdateId(node)); + } super.visitVariableSet(node); } diff --git a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart index c9b36793c4e..8b965442edf 100644 --- a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart +++ b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart @@ -292,6 +292,8 @@ Map computeExpectedMap(AnnotatedCode code) { Map map = {}; for (Annotation annotation in code.annotations) { IdValue idValue = IdValue.decode(annotation.offset, annotation.text); + Expect.isFalse(map.containsKey(idValue.id), + "Duplicate annotations for ${idValue.id}."); map[idValue.id] = idValue; } return map; diff --git a/tests/compiler/dart2js/equivalence/id_equivalence_test.dart b/tests/compiler/dart2js/equivalence/id_equivalence_test.dart index 1d9ee218d21..1ed42e30d4f 100644 --- a/tests/compiler/dart2js/equivalence/id_equivalence_test.dart +++ b/tests/compiler/dart2js/equivalence/id_equivalence_test.dart @@ -182,7 +182,9 @@ class ResolvedAstComputer extends AstDataExtractor with ComputerMixin { String dynamicName = getDynamicName(); if (dynamicName != null) return computeSetName(dynamicName); break; + case SendStructureKind.PREFIX: case SendStructureKind.POSTFIX: + case SendStructureKind.COMPOUND: String dynamicName = getDynamicName(); if (dynamicName != null) { if (id.kind == IdKind.update) { diff --git a/tests/compiler/dart2js/inference/data/locals.dart b/tests/compiler/dart2js/inference/data/locals.dart index 4ef0128215a..1e0839f28ea 100644 --- a/tests/compiler/dart2js/inference/data/locals.dart +++ b/tests/compiler/dart2js/inference/data/locals.dart @@ -9,6 +9,10 @@ main() { updatedLocal(); invokeLocal(); postfixLocal(); + postfixLocalUsed(); + prefixLocal(); + prefixLocalUsed(); + complexAssignmentLocal(); } /*element: uninitializedLocal:[null]*/ @@ -44,3 +48,29 @@ postfixLocal() { local2 /*invoke: [exact=JSUInt31]*/ ++; return null; } + +/*element: postfixLocalUsed:[exact=JSUInt31]*/ +postfixLocalUsed() { + var local2 = 0; + return local2 /*invoke: [exact=JSUInt31]*/ ++; +} + +/*element: prefixLocal:[null]*/ +prefixLocal() { + // ignore: UNUSED_LOCAL_VARIABLE + var local2 = 0; + /*invoke: [exact=JSUInt31]*/ ++local2; + return null; +} + +/*element: prefixLocalUsed:[subclass=JSUInt32]*/ +prefixLocalUsed() { + var local2 = 0; + return /*invoke: [exact=JSUInt31]*/ ++local2; +} + +/*element: complexAssignmentLocal:[subclass=JSUInt32]*/ +complexAssignmentLocal() { + var local2 = 0; + return local2 /*invoke: [exact=JSUInt31]*/ += 42; +}