// Copyright (c) 2020, 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. // @dart=2.7 // Requirements=nnbd-weak import 'package:expect/expect.dart'; import 'never_null_assignability_lib1.dart'; void takesLegacyObject(Object n) { // In a legacy library, we may get null. Throw AssertionError so that this // can be distinguished from a dynamic call failure. if (n == null) throw AssertionError("Not an Object"); } void takesLegacyInt(int n) { // In a legacy library, we may get null. Throw AssertionError so that this // can be distinguished from a dynamic call failure. if (n == null) throw AssertionError("Not an int"); } void takesLegacyNull(Null n) { // This should never happen! if (n != null) throw AssertionError("Not null"); } // Tests for direct calls to null safe functions. void testNullSafeCalls() { // Test calling a null safe function expecting Null from a legacy library { takesNull(nil); takesNull(never); // Even in weak mode, 3 can't be cast to Null or Never Expect.throwsTypeError(() => takesNull(3 as dynamic)); Expect.throwsTypeError(() => (takesNull as dynamic)(3)); } // Test calling a null safe function expecting Never from a legacy library { takesNever(nil); takesNever(never); // Even in weak mode, 3 can't be cast to Null or Never Expect.throwsTypeError(() => takesNever(3 as dynamic)); Expect.throwsTypeError(() => (takesNever as dynamic)(3)); } // Test calling a null safe function expecting int from a legacy library { takesInt(3); Expect.throwsAssertionError(() => takesInt(nil)); Expect.throwsAssertionError(() => takesInt(nil as dynamic)); Expect.throwsAssertionError(() => (takesInt as dynamic)(nil)); Expect.throwsTypeError(() => (takesInt as dynamic)("hello")); } // Test calling a null safe function expecting Object from a legacy library { takesObject(3); Expect.throwsAssertionError(() => takesObject(nil)); Expect.throwsAssertionError(() => takesObject(nil as dynamic)); Expect.throwsAssertionError(() => (takesObject as dynamic)(nil)); } // Test calling a null safe function expecting Object? from a legacy library { takesAny(3); takesAny(nil); (takesAny as dynamic)(nil); } } // Tests for direct calls to legacy functions. void testLegacyCalls() { // Test calling a legacy function expecting Null from a legacy library { takesLegacyNull(nil); // Even in weak mode, 3 can't be cast to Null or Never Expect.throwsTypeError(() => takesLegacyNull(3 as dynamic)); Expect.throwsTypeError(() => (takesLegacyNull as dynamic)(3)); } // Test calling a legacy function expecting int from a legacy library { takesLegacyInt(3); Expect.throwsAssertionError(() => takesLegacyInt(nil)); Expect.throwsAssertionError(() => (takesLegacyInt as dynamic)(nil)); Expect.throwsTypeError(() => (takesLegacyInt as dynamic)("hello")); } // Test calling a legacy function expecting Object from a legacy library { takesLegacyObject(3); Expect.throwsAssertionError(() => takesLegacyObject(nil)); Expect.throwsAssertionError(() => (takesLegacyObject as dynamic)(nil)); } } void testNullSafeApply() { // Test applying a null safe function of static type void Function(Null) // in a null safe library, when called with null cast to Null at the call // site. { applyTakesNull(takesNull, nil); applyTakesNull(takesNever, nil); applyTakesNull(takesAny, nil); // Cast of null to Null shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError(() => applyTakesNull(takesInt, nil)); // Cast of null to Null shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError(() => applyTakesNull(takesObject, nil)); } // Test applying a null safe function of static type void Function(Null) // in a null safe library, when called with a non-null value cast to Null // at the call site. { Expect.throwsTypeError(() => applyTakesNull(takesNull, 3)); Expect.throwsTypeError(() => applyTakesNull(takesNever, 3)); Expect.throwsTypeError(() => applyTakesNull(takesInt, 3)); Expect.throwsTypeError(() => applyTakesNull(takesObject, 3)); Expect.throwsTypeError(() => applyTakesNull(takesAny, 3)); } // Test applying a null safe function of static type void Function(Never) // in a null safe library, when called with null cast to Never at the call // site. { applyTakesNever(takesNull, nil); applyTakesNever(takesNever, nil); applyTakesNever(takesAny, nil); // Cast of null to Never shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError(() => applyTakesNever(takesInt, nil)); // Cast of null to Never shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError(() => applyTakesNever(takesObject, nil)); } // Test applying a null safe function of static type void Function(Never) // in a null safe library, when called with a non-null value cast to Never // at the call site. { Expect.throwsTypeError(() => applyTakesNever(takesNull, 3)); Expect.throwsTypeError(() => applyTakesNever(takesNever, 3)); Expect.throwsTypeError(() => applyTakesNever(takesInt, 3)); Expect.throwsTypeError(() => applyTakesNever(takesObject, 3)); Expect.throwsTypeError(() => applyTakesNever(takesAny, 3)); } } void testLegacyApply() { // Test applying a legacy function of static type void Function(Null) // in a null safe library, when called with null cast to Null at the call // site. { applyTakesNull(takesLegacyNull, nil); // Cast of null to Null shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError(() => applyTakesNull(takesLegacyInt, nil)); // Cast of null to Null shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError(() => applyTakesNull(takesLegacyObject, nil)); } // Test applying a legacy function of static type void Function(Null) // in a null safe library, when called with a non-null value cast to Null // at the call site. { Expect.throwsTypeError(() => applyTakesNull(takesLegacyNull, 3)); Expect.throwsTypeError(() => applyTakesNull(takesLegacyInt, 3)); Expect.throwsTypeError(() => applyTakesNull(takesLegacyObject, 3)); } // Test applying a legacy function of static type void Function(Never) // in a null safe library, when called with null cast to Never at the call // site. { applyTakesNever(takesLegacyNull, nil); // Cast of null to Never shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError(() => applyTakesNever(takesLegacyInt, nil)); // Cast of null to Never shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError(() => applyTakesNever(takesLegacyObject, nil)); } // Test applying a legacy function of static type void Function(Never) // in a null safe library, when called with a non-null value cast to Never // at the call site. { Expect.throwsTypeError(() => applyTakesNever(takesLegacyNull, 3)); Expect.throwsTypeError(() => applyTakesNever(takesLegacyInt, 3)); Expect.throwsTypeError(() => applyTakesNever(takesLegacyObject, 3)); } } void testNullSafeApplyDynamically() { // Test dynamically applying a null safe function of static type // void Function(Null) in a null safe library, when called with // null. { applyTakesNullDynamically(takesNull, nil); applyTakesNullDynamically(takesNever, nil); applyTakesNullDynamically(takesAny, nil); // Dynamic call shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError(() => applyTakesNullDynamically(takesInt, nil)); // Dynamic call shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError( () => applyTakesNullDynamically(takesObject, nil)); } // Test dynamically applying a null safe function of static type // void Function(Null) in a null safe library, when called with // a non-null value. { Expect.throwsTypeError(() => applyTakesNullDynamically(takesNull, 3)); Expect.throwsTypeError(() => applyTakesNullDynamically(takesNever, 3)); applyTakesNullDynamically(takesInt, 3); Expect.throwsTypeError(() => applyTakesNullDynamically(takesInt, "hello")); applyTakesNullDynamically(takesObject, 3); applyTakesNullDynamically(takesAny, 3); } // Test dynamically applying a null safe function of static type // void Function(Never) in a null safe library, when called with // null. { applyTakesNeverDynamically(takesNull, nil); applyTakesNeverDynamically(takesNever, nil); applyTakesNeverDynamically(takesAny, nil); // Dynamic call shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError( () => applyTakesNeverDynamically(takesInt, nil)); // Dynamic call shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError( () => applyTakesNeverDynamically(takesObject, nil)); } // Test dynamically applying a null safe function of static type // void Function(Never) in a null safe library, when called with // a non-null value. { Expect.throwsTypeError(() => applyTakesNeverDynamically(takesNull, 3)); Expect.throwsTypeError(() => applyTakesNeverDynamically(takesNever, 3)); applyTakesNeverDynamically(takesInt, 3); Expect.throwsTypeError(() => applyTakesNeverDynamically(takesInt, "hello")); applyTakesNeverDynamically(takesObject, 3); applyTakesNeverDynamically(takesAny, 3); } } void testLegacyApplyDynamically() { // Test dynamically applying a legacy function of static type // void Function(Null) in a null safe library, when called with // null. { applyTakesNullDynamically(takesLegacyNull, nil); // Dynamic call shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError( () => applyTakesNullDynamically(takesLegacyInt, nil)); // Dynamic call shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError( () => applyTakesNullDynamically(takesLegacyObject, nil)); } // Test dynamically applying a legacy function of static type // void Function(Null) in a null safe library, when called with // a non-null value. { Expect.throwsTypeError(() => applyTakesNullDynamically(takesLegacyNull, 3)); applyTakesNullDynamically(takesLegacyInt, 3); Expect.throwsTypeError( () => applyTakesNullDynamically(takesLegacyInt, "hello")); applyTakesNullDynamically(takesLegacyObject, 3); } // Test dynamically applying a legacy function of static type // void Function(Never) in a null safe library, when called with // null. { applyTakesNeverDynamically(takesLegacyNull, nil); // Dynamic call shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError( () => applyTakesNeverDynamically(takesLegacyInt, nil)); // Dynamic call shouldn't fail, check that we reach the assertion. Expect.throwsAssertionError( () => applyTakesNeverDynamically(takesLegacyObject, nil)); } // Test dynamically applying a legacy function of static type // void Function(Never) in a null safe library, when called with // a non-null value. { Expect.throwsTypeError( () => applyTakesNeverDynamically(takesLegacyNull, 3)); applyTakesNeverDynamically(takesLegacyInt, 3); Expect.throwsTypeError( () => applyTakesNeverDynamically(takesLegacyInt, "hello")); applyTakesNeverDynamically(takesLegacyObject, 3); } } void main() { never = null; never = nil; nil = never; testNullSafeCalls(); testLegacyCalls(); testNullSafeApply(); testLegacyApply(); testNullSafeApplyDynamically(); testLegacyApplyDynamically(); }