add migration engine support for top level var reference

Change-Id: I77039243bc098449e4af976d2500c4d28f9f4012
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106562
Commit-Queue: Dan Rubel <danrubel@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/nnbd_migration/lib/src/graph_builder.dart b/pkg/nnbd_migration/lib/src/graph_builder.dart
index 30029c3..6f99c8a 100644
--- a/pkg/nnbd_migration/lib/src/graph_builder.dart
+++ b/pkg/nnbd_migration/lib/src/graph_builder.dart
@@ -626,6 +626,9 @@
     if (staticElement is ParameterElement ||
         staticElement is LocalVariableElement) {
       return getOrComputeElementType(staticElement);
+    } else if (staticElement is PropertyAccessorElement) {
+      // TODO(danrubel): assuming getter context... need to handle setter
+      return getOrComputeElementType(staticElement).returnType;
     } else if (staticElement is ClassElement) {
       return _nonNullableTypeType;
     } else {
@@ -724,10 +727,14 @@
         guards: _guards, hard: hard);
     expressionChecks?.edges?.add(edge);
     // TODO(paulberry): generalize this.
+
     if ((_isSimple(sourceType) || destinationType.type.isObject) &&
         _isSimple(destinationType)) {
       // Ok; nothing further to do.
-    } else if (sourceType.type is InterfaceType &&
+      return;
+    }
+
+    if (sourceType.type is InterfaceType &&
         destinationType.type is InterfaceType &&
         sourceType.type.element == destinationType.type.element) {
       assert(sourceType.typeArguments.length ==
@@ -737,11 +744,16 @@
             sourceType.typeArguments[i], expressionChecks,
             hard: false);
       }
-    } else if (destinationType.type.isDynamic || sourceType.type.isDynamic) {
-      // ok; nothing further to do.
-    } else {
-      throw '$destinationType <= $sourceType'; // TODO(paulberry)
+      return;
     }
+
+    if (destinationType.type.isDynamic || sourceType.type.isDynamic) {
+      // ok; nothing further to do.
+      return;
+    }
+
+    // TODO(paulberry)
+    throw '$destinationType <= $sourceType';
   }
 
   /// Double checks that [name] is not the name of a method or getter declared
diff --git a/pkg/nnbd_migration/test/graph_builder_test.dart b/pkg/nnbd_migration/test/graph_builder_test.dart
index 9f516d6..f3a938e 100644
--- a/pkg/nnbd_migration/test/graph_builder_test.dart
+++ b/pkg/nnbd_migration/test/graph_builder_test.dart
@@ -1638,6 +1638,20 @@
     assertNoUpstreamNullability(decoratedTypeAnnotation('int').node);
   }
 
+  test_topLevelVar_reference() async {
+    await analyze('''
+double pi = 3.1415;
+double get myPi => pi;
+''');
+    var pi = findNode.topLevelVariableDeclaration('double pi');
+    var piType =
+        variables.decoratedTypeAnnotation(testSource, pi.variables.type);
+    var myPi = findNode.any('myPi').parent as FunctionDeclaration;
+    var myPiType =
+        variables.decoratedTypeAnnotation(testSource, myPi.returnType);
+    assertEdge(piType.node, myPiType.node, hard: false);
+  }
+
   test_type_argument_explicit_bound() async {
     await analyze('''
 class C<T extends Object> {}