blob: a5f9b7e1ed664415a69404ed8a84863e35de0d1b [file] [log] [blame]
// Copyright (c) 2024, 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.
// These checks are not implemented in the analyzer. If we ever decide to
// implement the static checks in the analyzer, move this test into the
// static_checks subdir to prevent analyzer errors showing up in the IDE.
import 'dart:ffi';
import 'dart:typed_data';
void main() {
testInstantiateDeeplyImmutable();
}
@pragma('vm:deeply-immutable')
final class EmptyClass {}
@pragma('vm:deeply-immutable')
final class Class1 {
Class1(this.a);
int a;
// ^
// [cfe] Deeply immutable classes must only have final non-late instance fields.
}
@pragma('vm:deeply-immutable')
final class Class2 {
late final int a;
// ^
// [cfe] Deeply immutable classes must only have final non-late instance fields.
}
@pragma('vm:deeply-immutable')
final class Class3 {
Class3(this.a);
final int a;
}
@pragma('vm:deeply-immutable')
final class Class4 {
// Static fields are not part of the instance.
static late final int a;
}
@pragma('vm:deeply-immutable')
final class Class5 {
// External fields are defined as setter/getter pairs.
external int a;
}
final class NotDeeplyImmutable {
late int a;
}
@pragma('vm:deeply-immutable')
final class Class6 {
Class6(this.a);
final NotDeeplyImmutable a;
// ^
// [cfe] Deeply immutable classes must only have deeply immutable instance fields. Deeply immutable types include 'int', 'double', 'bool', 'String', 'Pointer', 'Float32x4', 'Float64x2', 'Int32x4', and classes annotated with `@pragma('vm:deeply-immutable')`.
}
void testInstantiateDeeplyImmutable() {
Class7(
someString: 'someString',
someNullableString: 'someString',
someInt: 3,
someDouble: 3.3,
someBool: false,
someNull: null,
someInt32x4: Int32x4(0, 1, 2, 3),
someFloat32x4: Float32x4(0.0, 1.1, 2.2, 3.3),
someFloat64x2: Float64x2(4.4, 5.5),
someClass7: Class7(
someString: 'someString',
someInt: 3,
someDouble: 3.3,
someBool: false,
someNull: null,
someInt32x4: Int32x4(0, 1, 2, 3),
someFloat32x4: Float32x4(0.0, 1.1, 2.2, 3.3),
someFloat64x2: Float64x2(4.4, 5.5),
someClass7: null,
somePointer: Pointer.fromAddress(0x8badf00d),
),
somePointer: Pointer.fromAddress(0xdeadbeef),
);
}
@pragma('vm:deeply-immutable')
final class Class7 {
final String someString;
final String? someNullableString;
final int someInt;
final double someDouble;
final bool someBool;
final Null someNull;
final Int32x4 someInt32x4;
final Float32x4 someFloat32x4;
final Float64x2 someFloat64x2;
final Class7? someClass7;
final Pointer somePointer;
// Note that UnmodifiableUint8ListView has been deprecated. Which means there
// currently is no way to intentionally have a typed data as a field in a
// class which is deeply immutable.
// See: https://github.com/dart-lang/sdk/issues/53218.
// Note that RegExp, SendPort, and Capability can be implemented. So fields
// are not allowed to be of these types either.
Class7({
required this.someString,
this.someNullableString,
required this.someInt,
required this.someDouble,
required this.someBool,
required this.someNull,
required this.someInt32x4,
required this.someFloat32x4,
required this.someFloat64x2,
required this.someClass7,
required this.somePointer,
});
}
void testInstantiateImmutableHierarchy() {
Class8(
animal: Cat(
numberOfLegs: 4,
averageNumberOfMeowsPerDay: 42.0,
),
);
Class8(
animal: Dog(
numberOfLegs: 4,
averageNumberOfWoofsPerDay: 1337.0,
),
);
}
@pragma('vm:deeply-immutable')
final class Animal {
final int numberOfLegs;
Animal({
required this.numberOfLegs,
});
}
@pragma('vm:deeply-immutable')
final class Cat extends Animal {
final double averageNumberOfMeowsPerDay;
Cat({
required super.numberOfLegs,
required this.averageNumberOfMeowsPerDay,
});
}
@pragma('vm:deeply-immutable')
final class Dog extends Animal {
final double averageNumberOfWoofsPerDay;
Dog({
required super.numberOfLegs,
required this.averageNumberOfWoofsPerDay,
});
}
@pragma('vm:deeply-immutable')
final class Class8 {
final Animal animal;
Class8({
required this.animal,
});
}
@pragma('vm:deeply-immutable')
abstract final class DeeplyImmutableInterface {}
@pragma('vm:deeply-immutable')
final class Class9 implements DeeplyImmutableInterface {}
@pragma('vm:deeply-immutable')
final class Class10 implements DeeplyImmutableInterface {}
@pragma('vm:deeply-immutable')
sealed class Class11 {}
@pragma('vm:deeply-immutable')
class NotSealedOrFinalClass {}
// ^^^^^^^^^^^^^^^^^^^^^
// [cfe] Deeply immutable classes must be final or sealed.
final class Class12 extends DeeplyImmutableInterface {}
// ^^^^^^^
// [cfe] Subtypes of deeply immutable classes must be deeply immutable.
final class Class13 implements DeeplyImmutableInterface {
// ^^^^^^^
// [cfe] Subtypes of deeply immutable classes must be deeply immutable.
}
@pragma('vm:deeply-immutable')
final class Class14<T extends DeeplyImmutableInterface> {
final T deeplyImmutable;
Class14({required this.deeplyImmutable});
}
@pragma('vm:deeply-immutable')
final class Class15<T extends NotDeeplyImmutable> {
final T notDeeplyImmutable;
// ^^^^^^^^^^^^^^^^^^
// [cfe] Deeply immutable classes must only have deeply immutable instance fields. Deeply immutable types include 'int', 'double', 'bool', 'String', 'Pointer', 'Float32x4', 'Float64x2', 'Int32x4', and classes annotated with `@pragma('vm:deeply-immutable')`.
Class15({required this.notDeeplyImmutable});
}
@pragma('vm:deeply-immutable')
abstract mixin class Class17 {}
// ^^^^^^^
// [cfe] Deeply immutable classes must be final or sealed.