[VM/runtime] Fix optimization for reusing instantiator type argument vector.

The bit vector representing the nullability of the types of a type argument vector was stored in reverse order.
This caused a problem when a longer instantiated vector is reused for a shorter uninstantiated vector.

This fixes https://github.com/dart-lang/sdk/issues/45529

TEST=added regression test

Change-Id: I0e936e45d51fa896d7562f4f03c8878437eb464f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193751
Commit-Queue: RĂ©gis Crelier <regis@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e82c80d..bbe41e4 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -5976,23 +5976,24 @@
   if (num_types <= kNullabilityMaxTypes) {
     AbstractType& type = AbstractType::Handle();
     for (intptr_t i = 0; i < num_types; i++) {
-      result <<= kNullabilityBitsPerType;
       type = TypeAt(i);
+      intptr_t type_bits = 0;
       if (!type.IsNull() && !type.IsNullTypeRef()) {
         switch (type.nullability()) {
           case Nullability::kNullable:
-            result |= kNullableBits;
+            type_bits = kNullableBits;
             break;
           case Nullability::kNonNullable:
-            result |= kNonNullableBits;
+            type_bits = kNonNullableBits;
             break;
           case Nullability::kLegacy:
-            result |= kLegacyBits;
+            type_bits = kLegacyBits;
             break;
           default:
             UNREACHABLE();
         }
       }
+      result |= (type_bits << (i * kNullabilityBitsPerType));
     }
   }
   set_nullability(result);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 6a4b5bb..259e3df 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -7368,10 +7368,12 @@
   // 2 bits per type:
   //  - the high bit is set if the type is nullable or legacy.
   //  - the low bit is set if the type is nullable.
-  // The nullabilty is 0 if the vector is longer than kNullabilityMaxTypes.
+  // The nullability is 0 if the vector is longer than kNullabilityMaxTypes.
   // The condition evaluated at runtime to decide whether UTA can share ITA is
   //   (UTA.nullability & ITA.nullability) == UTA.nullability
-  // Note that this allows for ITA to be longer than UTA.
+  // Note that this allows for ITA to be longer than UTA (the bit vector must be
+  // stored in the same order as the corresponding type vector, i.e. with the
+  // least significant 2 bits representing the nullability of the first type).
   static const intptr_t kNullabilityBitsPerType = 2;
   static const intptr_t kNullabilityMaxTypes =
       kSmiBits / kNullabilityBitsPerType;
diff --git a/tests/language/regress/regress45529_test.dart b/tests/language/regress/regress45529_test.dart
new file mode 100644
index 0000000..6cd4ed2
--- /dev/null
+++ b/tests/language/regress/regress45529_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2021, 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.
+
+import "package:expect/expect.dart";
+
+void main() {
+  final baz = Foo<Null>().baz;
+  Expect.equals("Baz<Bar<Null>?>", baz.runtimeType.toString());
+  baz.v = baz.v;
+}
+
+class Bar<T> {}
+
+class Foo<T> extends Quux<Bar<T>> {}
+
+class Baz<T> {
+  Baz(this.v);
+  T v;
+}
+
+class Quux<T> {
+  final baz = Baz<T?>(null);
+}