// Copyright (c) 2019, 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.
// VMOptions=--optimization-counter-threshold=10 --no-background-compilation

// This test checks for obscure interaction between LICM and AssertAssignable
// strengthening performed by Type Propagator. The later would use deopt_id
// from an environment attached to AssertAssignable, and this deopt id under
// certain conditions would be set to -1. The code was changed to never
// use deopt_id from the environment but this regression test is provided for
// completeness.

class A<T> {
  var foo = 42;
}

class B extends A<String> {}

class C extends B {}

void foo(dynamic a) {
  // To prevent AssertAssignable strengthening from occurring too early we
  // need to hide the fact that CheckClass and AssertAssignable are performed
  // against the same SSA value. To achieve that we store a into an array and
  // then load it back. Load Forwarding would happen just before LICM and
  // will remove the indirection. Then LICM would hoist both CheckClass
  // and AssertAssignable out of the loop and then strengthening would happen.
  final box = <dynamic>[null];
  box[0] = a;

  for (var i = 0; i < 1; i++) {
    a as A<String>;
    if (box[0].foo != 42) {
      throw "unexpected";
    }
  }
}

void main() {
  for (var i = 0; i < 100; i++) {
    foo(B());
  }

  // Trigger deoptimization on the CheckClass produced by strengthened
  // AssertAssignable - if this CheckClass has wrong deoptimization id a crash
  // would occur.
  foo(C());
}
