[cfe] Warn on null aware access on this and static members

Closes #43703
Closes #43461

Change-Id: I861462b5fcf31d5459c17cbe1604ce285c359dec
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/167563
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther 2020-10-15 08:48:33 +00:00 committed by commit-bot@chromium.org
parent 2350776a1c
commit 16f7ce8e57
29 changed files with 2157 additions and 286 deletions

View file

@ -959,6 +959,29 @@ const MessageCode messageClassInClass = const MessageCode("ClassInClass",
message: r"""Classes can't be declared inside other classes.""",
tip: r"""Try moving the class to the top-level.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String name)> templateClassInNullAwareReceiver =
const Template<Message Function(String name)>(
messageTemplate: r"""The class '#name' cannot be null.""",
tipTemplate: r"""Try replacing '?.' with '.'""",
withArguments: _withArgumentsClassInNullAwareReceiver);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String name)> codeClassInNullAwareReceiver =
const Code<Message Function(String name)>(
"ClassInNullAwareReceiver", templateClassInNullAwareReceiver,
severity: Severity.warning);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsClassInNullAwareReceiver(String name) {
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
return new Message(codeClassInNullAwareReceiver,
message: """The class '${name}' cannot be null.""",
tip: """Try replacing '?.' with '.'""",
arguments: {'name': name});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeColonInPlaceOfIn = messageColonInPlaceOfIn;
@ -8845,6 +8868,16 @@ const MessageCode messageThisAsIdentifier = const MessageCode(
analyzerCodes: <String>["INVALID_REFERENCE_TO_THIS"],
message: r"""Expected identifier, but got 'this'.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeThisInNullAwareReceiver = messageThisInNullAwareReceiver;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageThisInNullAwareReceiver = const MessageCode(
"ThisInNullAwareReceiver",
severity: Severity.warning,
message: r"""The receiver 'this' cannot be null.""",
tip: r"""Try replacing '?.' with '.'""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String string)>
templateThisOrSuperAccessInFieldInitializer =

View file

@ -560,7 +560,8 @@ class PropertyAccessGenerator extends Generator {
static Generator make(ExpressionGeneratorHelper helper, Token token,
Expression receiver, Name name, bool isNullAware) {
if (helper.forest.isThisExpression(receiver)) {
return new ThisPropertyAccessGenerator(helper, token, name);
return new ThisPropertyAccessGenerator(helper, token, name,
thisOffset: receiver.fileOffset, isNullAware: isNullAware);
} else {
return isNullAware
? new NullAwarePropertyAccessGenerator(helper, token, receiver, name)
@ -603,8 +604,13 @@ class ThisPropertyAccessGenerator extends Generator {
/// documentation.
final Name name;
/// The offset of `this` if explicit. Otherwise `null`.
final int thisOffset;
final bool isNullAware;
ThisPropertyAccessGenerator(
ExpressionGeneratorHelper helper, Token token, this.name)
ExpressionGeneratorHelper helper, Token token, this.name,
{this.thisOffset, this.isNullAware: false})
: super(helper, token);
@override
@ -613,18 +619,30 @@ class ThisPropertyAccessGenerator extends Generator {
@override
String get _plainNameForRead => name.text;
void _reportNonNullableInNullAwareWarningIfNeeded() {
if (isNullAware && _helper.libraryBuilder.isNonNullableByDefault) {
_helper.libraryBuilder.addProblem(
messageThisInNullAwareReceiver,
thisOffset ?? fileOffset,
thisOffset != null ? 4 : noLength,
_helper.uri);
}
}
@override
Expression buildSimpleRead() {
return _createRead();
}
Expression _createRead() {
_reportNonNullableInNullAwareWarningIfNeeded();
return _forest.createPropertyGet(
fileOffset, _forest.createThisExpression(fileOffset), name);
}
@override
Expression buildAssignment(Expression value, {bool voidContext: false}) {
_reportNonNullableInNullAwareWarningIfNeeded();
return _createWrite(fileOffset, value, forEffect: voidContext);
}
@ -649,6 +667,7 @@ class ThisPropertyAccessGenerator extends Generator {
bool voidContext: false,
bool isPreIncDec: false,
bool isPostIncDec: false}) {
_reportNonNullableInNullAwareWarningIfNeeded();
_helper.forest.createBinary(
offset,
_forest.createPropertyGet(
@ -672,6 +691,7 @@ class ThisPropertyAccessGenerator extends Generator {
return buildCompoundAssignment(binaryOperator, value,
offset: offset, voidContext: voidContext, isPostIncDec: true);
}
_reportNonNullableInNullAwareWarningIfNeeded();
VariableDeclaration read = _helper.forest.createVariableDeclarationForValue(
_forest.createPropertyGet(
fileOffset, _forest.createThisExpression(fileOffset), name));
@ -1096,7 +1116,8 @@ class IndexedAccessGenerator extends Generator {
{bool isNullAware}) {
assert(isNullAware != null);
if (helper.forest.isThisExpression(receiver)) {
return new ThisIndexedAccessGenerator(helper, token, index);
return new ThisIndexedAccessGenerator(helper, token, index,
thisOffset: receiver.fileOffset, isNullAware: isNullAware);
} else {
return new IndexedAccessGenerator(helper, token, receiver, index,
isNullAware: isNullAware);
@ -1109,8 +1130,12 @@ class IndexedAccessGenerator extends Generator {
class ThisIndexedAccessGenerator extends Generator {
final Expression index;
final int thisOffset;
final bool isNullAware;
ThisIndexedAccessGenerator(
ExpressionGeneratorHelper helper, Token token, this.index)
ExpressionGeneratorHelper helper, Token token, this.index,
{this.thisOffset, this.isNullAware: false})
: super(helper, token);
@override
@ -1119,14 +1144,26 @@ class ThisIndexedAccessGenerator extends Generator {
@override
String get _debugName => "ThisIndexedAccessGenerator";
void _reportNonNullableInNullAwareWarningIfNeeded() {
if (isNullAware && _helper.libraryBuilder.isNonNullableByDefault) {
_helper.libraryBuilder.addProblem(
messageThisInNullAwareReceiver,
thisOffset ?? fileOffset,
thisOffset != null ? 4 : noLength,
_helper.uri);
}
}
@override
Expression buildSimpleRead() {
_reportNonNullableInNullAwareWarningIfNeeded();
Expression receiver = _helper.forest.createThisExpression(fileOffset);
return _forest.createIndexGet(fileOffset, receiver, index);
}
@override
Expression buildAssignment(Expression value, {bool voidContext: false}) {
_reportNonNullableInNullAwareWarningIfNeeded();
Expression receiver = _helper.forest.createThisExpression(fileOffset);
return _forest.createIndexSet(fileOffset, receiver, index, value,
forEffect: voidContext, readOnlyReceiver: true);
@ -1135,6 +1172,7 @@ class ThisIndexedAccessGenerator extends Generator {
@override
Expression buildIfNullAssignment(Expression value, DartType type, int offset,
{bool voidContext: false}) {
_reportNonNullableInNullAwareWarningIfNeeded();
Expression receiver = _helper.forest.createThisExpression(fileOffset);
return new IfNullIndexSet(receiver, index, value,
readOffset: fileOffset,
@ -1150,6 +1188,7 @@ class ThisIndexedAccessGenerator extends Generator {
bool voidContext: false,
bool isPreIncDec: false,
bool isPostIncDec: false}) {
_reportNonNullableInNullAwareWarningIfNeeded();
Expression receiver = _helper.forest.createThisExpression(fileOffset);
return new CompoundIndexSet(receiver, index, binaryOperator, value,
readOffset: fileOffset,
@ -1348,8 +1387,13 @@ class StaticAccessGenerator extends Generator {
/// without a corresponding setter.
final Member writeTarget;
/// The offset of the type name if explicit. Otherwise `null`.
final int typeOffset;
final bool isNullAware;
StaticAccessGenerator(ExpressionGeneratorHelper helper, Token token,
this.targetName, this.readTarget, this.writeTarget)
this.targetName, this.readTarget, this.writeTarget,
{this.typeOffset, this.isNullAware: false})
: assert(targetName != null),
assert(readTarget != null || writeTarget != null),
super(helper, token);
@ -1359,9 +1403,23 @@ class StaticAccessGenerator extends Generator {
String targetName,
Token token,
MemberBuilder getterBuilder,
MemberBuilder setterBuilder) {
MemberBuilder setterBuilder,
{int typeOffset,
bool isNullAware: false}) {
return new StaticAccessGenerator(helper, token, targetName,
getterBuilder?.readTarget, setterBuilder?.writeTarget);
getterBuilder?.readTarget, setterBuilder?.writeTarget,
typeOffset: typeOffset, isNullAware: isNullAware);
}
void _reportNonNullableInNullAwareWarningIfNeeded() {
if (isNullAware && _helper.libraryBuilder.isNonNullableByDefault) {
String className = (readTarget ?? writeTarget).enclosingClass.name;
_helper.libraryBuilder.addProblem(
templateClassInNullAwareReceiver.withArguments(className),
typeOffset ?? fileOffset,
typeOffset != null ? className.length : noLength,
_helper.uri);
}
}
@override
@ -1380,6 +1438,7 @@ class StaticAccessGenerator extends Generator {
if (readTarget == null) {
read = _makeInvalidRead();
} else {
_reportNonNullableInNullAwareWarningIfNeeded();
read = _helper.makeStaticGet(readTarget, token);
}
return read;
@ -1387,6 +1446,7 @@ class StaticAccessGenerator extends Generator {
@override
Expression buildAssignment(Expression value, {bool voidContext = false}) {
_reportNonNullableInNullAwareWarningIfNeeded();
return _createWrite(fileOffset, value);
}
@ -1395,6 +1455,7 @@ class StaticAccessGenerator extends Generator {
if (writeTarget == null) {
write = _makeInvalidWrite(value);
} else {
_reportNonNullableInNullAwareWarningIfNeeded();
write = new StaticSet(writeTarget, value)..fileOffset = offset;
}
return write;
@ -3043,10 +3104,6 @@ class TypeUseGenerator extends ReadOnlyAccessGenerator {
@override
buildPropertyAccess(
IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
// `SomeType?.toString` is the same as `SomeType.toString`, not
// `(SomeType).toString`.
isNullAware = false;
Name name = send.name;
Arguments arguments = send.arguments;
@ -3107,7 +3164,9 @@ class TypeUseGenerator extends ReadOnlyAccessGenerator {
name.text,
send.token,
member is MemberBuilder ? member : null,
setter is MemberBuilder ? setter : null);
setter is MemberBuilder ? setter : null,
typeOffset: fileOffset,
isNullAware: isNullAware);
}
return arguments == null
@ -3116,6 +3175,8 @@ class TypeUseGenerator extends ReadOnlyAccessGenerator {
offsetForToken(send.token), send.typeArguments, arguments,
isTypeArgumentsInForest: send.isTypeArgumentsInForest);
} else {
// `SomeType?.toString` is the same as `SomeType.toString`, not
// `(SomeType).toString`.
return super.buildPropertyAccess(send, operatorOffset, isNullAware);
}
}
@ -4132,6 +4193,13 @@ class ThisAccessGenerator extends Generator {
];
}
void _reportNonNullableInNullAwareWarningIfNeeded() {
if (_helper.libraryBuilder.isNonNullableByDefault) {
_helper.libraryBuilder.addProblem(
messageThisInNullAwareReceiver, fileOffset, 4, _helper.uri);
}
}
buildPropertyAccess(
IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
Name name = send.name;
@ -4150,6 +4218,9 @@ class ThisAccessGenerator extends Generator {
if (send is SendAccessGenerator) {
// Notice that 'this' or 'super' can't be null. So we can ignore the
// value of [isNullAware].
if (isNullAware) {
_reportNonNullableInNullAwareWarningIfNeeded();
}
return _helper.buildMethodInvocation(
_forest.createThisExpression(fileOffset),
name,
@ -4173,7 +4244,9 @@ class ThisAccessGenerator extends Generator {
_helper,
// TODO(ahe): This is not the 'this' token.
send.token,
name);
name,
thisOffset: fileOffset,
isNullAware: isNullAware);
}
}
}
@ -4313,7 +4386,8 @@ class ThisAccessGenerator extends Generator {
_helper.lookupInstanceMember(indexGetName, isSuper: true),
_helper.lookupInstanceMember(indexSetName, isSuper: true));
} else {
return new ThisIndexedAccessGenerator(_helper, token, index);
return new ThisIndexedAccessGenerator(_helper, token, index,
thisOffset: fileOffset, isNullAware: isNullAware);
}
}

View file

@ -1165,21 +1165,26 @@ class InferenceVisitor
DartType inferredType = inferrer.typeSchemaEnvironment
.getStandardUpperBound(nonNullableLhsType, rhsResult.inferredType,
inferrer.library.library);
VariableDeclaration variable =
createVariable(lhsResult.expression, lhsResult.inferredType);
MethodInvocation equalsNull = createEqualsNull(
lhsResult.expression.fileOffset,
createVariableGet(variable),
equalsMember);
VariableGet variableGet = createVariableGet(variable);
if (inferrer.library.isNonNullableByDefault &&
!identical(nonNullableLhsType, originalLhsType)) {
variableGet.promotedType = nonNullableLhsType;
Expression replacement;
if (lhsResult.expression is ThisExpression) {
replacement = lhsResult.expression;
} else {
VariableDeclaration variable =
createVariable(lhsResult.expression, lhsResult.inferredType);
MethodInvocation equalsNull = createEqualsNull(
lhsResult.expression.fileOffset,
createVariableGet(variable),
equalsMember);
VariableGet variableGet = createVariableGet(variable);
if (inferrer.library.isNonNullableByDefault &&
!identical(nonNullableLhsType, originalLhsType)) {
variableGet.promotedType = nonNullableLhsType;
}
ConditionalExpression conditional = new ConditionalExpression(
equalsNull, rhsResult.expression, variableGet, inferredType);
replacement = new Let(variable, conditional)
..fileOffset = node.fileOffset;
}
ConditionalExpression conditional = new ConditionalExpression(
equalsNull, rhsResult.expression, variableGet, inferredType);
Expression replacement = new Let(variable, conditional)
..fileOffset = node.fileOffset;
return new ExpressionInferenceResult(inferredType, replacement);
}

View file

@ -63,6 +63,7 @@ CantUsePrefixAsExpression/part_wrapped_script: Fail # Importing file in the (now
CantUsePrefixWithNullAware/part_wrapped_script: Fail # Importing file in the (now) part.
CantUseSuperBoundedTypeForInstanceCreation/analyzerCode: Fail
CantUseSuperBoundedTypeForInstanceCreation/example: Fail
ClassInNullAwareReceiver/analyzerCode: Fail
ColonInPlaceOfIn/example: Fail
ConflictingModifiers/part_wrapped_script1: Fail
ConflictingModifiers/script1: Fail
@ -711,6 +712,7 @@ SwitchExpressionUserDefinedEquals/example: Fail
SyntheticToken/example: Fail # Can't be tested, used to recover from other errors.
ThisAccessInFieldInitializer/example: Fail
ThisAsIdentifier/example: Fail
ThisInNullAwareReceiver/analyzerCode: Fail
ThisOrSuperAccessInFieldInitializer/example: Fail
ThrowingNotAssignableToObjectError/analyzerCode: Fail
ThrowingNotAssignableToObjectError/example: Fail

View file

@ -4400,6 +4400,32 @@ NonNullableInNullAware:
template: "Operand of null-aware operation '#name' has type '#type' which excludes null."
severity: WARNING
ThisInNullAwareReceiver:
template: "The receiver 'this' cannot be null."
tip: "Try replacing '?.' with '.'"
severity: WARNING
configuration: nnbd-strong
script: |
class C {
var field;
method() {
this?.field;
}
}
ClassInNullAwareReceiver:
template: "The class '#name' cannot be null."
tip: "Try replacing '?.' with '.'"
severity: WARNING
configuration: nnbd-strong
script: |
class C {
static var field;
}
method() {
C?.field;
}
NonNullableNotAssignedError:
template: "Non-nullable variable '#name' must be assigned before it can be used."
configuration: nnbd-strong

View file

@ -0,0 +1,30 @@
// 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.
class C {
static int get staticMember => 0;
static void set staticMember(int value) {}
static int? get staticMember2 => 0;
static void set staticMember2(int? value) {}
static void staticMethod() {}
static List<int> get property => [0];
static Map<int, int?> get property2 => {};
}
void main() {
C?.staticMember;
C?.staticMember;
C?.staticMember = 42;
C?.staticMethod();
C?.staticMember.isEven;
C?.staticMember.toString();
C?.property[0];
C?.property[0] = 0;
C?.property2[0] ??= 0;
C?.staticMember2 ??= 42;
C?.staticMember += 2;
C?.staticMember++;
--C?.staticMember;
}

View file

@ -0,0 +1,24 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class C extends core::Object {
synthetic constructor •() → self::C
;
static get staticMember() → core::int
;
static set staticMember(core::int value) → void
;
static get staticMember2() → core::int?
;
static set staticMember2(core::int? value) → void
;
static method staticMethod() → void
;
static get property() → core::List<core::int>
;
static get property2() → core::Map<core::int, core::int?>
;
}
static method main() → void
;

View file

@ -0,0 +1,98 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:17:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:18:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:19:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember = 42;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:21:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember.isEven;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:22:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember.toString();
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:23:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property[0];
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:24:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property[0] = 0;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:25:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property2[0] ??= 0;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:26:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember2 ??= 42;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:27:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember += 2;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:28:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember++;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:29:5: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// --C?.staticMember;
// ^
//
import self as self;
import "dart:core" as core;
class C extends core::Object {
synthetic constructor •() → self::C
: super core::Object::•()
;
static get staticMember() → core::int
return 0;
static set staticMember(core::int value) → void {}
static get staticMember2() → core::int?
return 0;
static set staticMember2(core::int? value) → void {}
static method staticMethod() → void {}
static get property() → core::List<core::int>
return <core::int>[0];
static get property2() → core::Map<core::int, core::int?>
return <core::int, core::int?>{};
}
static method main() → void {
self::C::staticMember;
self::C::staticMember;
self::C::staticMember = 42;
self::C::staticMethod();
self::C::staticMember.{core::int::isEven};
self::C::staticMember.{core::int::toString}();
self::C::property.{core::List::[]}(0);
self::C::property.{core::List::[]=}(0, 0);
let final core::Map<core::int, core::int?> #t1 = self::C::property2 in let final core::int #t2 = 0 in #t1.{core::Map::[]}(#t2).{core::num::==}(null) ?{core::int} #t1.{core::Map::[]=}(#t2, 0) : null;
self::C::staticMember2.{core::num::==}(null) ?{core::int} self::C::staticMember2 = 42 : null;
self::C::staticMember = self::C::staticMember.{core::num::+}(2);
self::C::staticMember = self::C::staticMember.{core::num::+}(1);
self::C::staticMember = self::C::staticMember.{core::num::-}(1);
}

View file

@ -0,0 +1,104 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:17:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:18:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:19:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember = 42;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:21:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember.isEven;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:22:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember.toString();
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:23:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property[0];
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:24:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property[0] = 0;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:25:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property2[0] ??= 0;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:26:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember2 ??= 42;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:27:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember += 2;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:28:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember++;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:29:5: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// --C?.staticMember;
// ^
//
import self as self;
import "dart:core" as core;
class C extends core::Object {
synthetic constructor •() → self::C
: super core::Object::•()
;
static get staticMember() → core::int
return 0;
static set staticMember(core::int value) → void {}
static get staticMember2() → core::int?
return 0;
static set staticMember2(core::int? value) → void {}
static method staticMethod() → void {}
static get property() → core::List<core::int>
return <core::int>[0];
static get property2() → core::Map<core::int, core::int?>
return <core::int, core::int?>{};
}
static method main() → void {
self::C::staticMember;
self::C::staticMember;
self::C::staticMember = 42;
self::C::staticMethod();
self::C::staticMember.{core::int::isEven};
self::C::staticMember.{core::int::toString}();
self::C::property.{core::List::[]}(0);
self::C::property.{core::List::[]=}(0, 0);
let final core::Map<core::int, core::int?> #t1 = self::C::property2 in let final core::int #t2 = 0 in #t1.{core::Map::[]}(#t2).{core::num::==}(null) ?{core::int} #t1.{core::Map::[]=}(#t2, 0) : null;
self::C::staticMember2.{core::num::==}(null) ?{core::int} self::C::staticMember2 = 42 : null;
self::C::staticMember = self::C::staticMember.{core::num::+}(2);
self::C::staticMember = self::C::staticMember.{core::num::+}(1);
self::C::staticMember = self::C::staticMember.{core::num::-}(1);
}
Extra constant evaluation status:
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_static_access.dart:25:16 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_static_access.dart:25:16 -> IntConstant(0)
Extra constant evaluation: evaluated: 38, effectively constant: 2

View file

@ -0,0 +1,11 @@
class C {
static int get staticMember => 0;
static void set staticMember(int value) {}
static int? get staticMember2 => 0;
static void set staticMember2(int? value) {}
static void staticMethod() {}
static List<int> get property => [0];
static Map<int, int?> get property2 => {};
}
void main() {}

View file

@ -0,0 +1,11 @@
class C {
static List<int> get property => [0];
static Map<int, int?> get property2 => {};
static int? get staticMember2 => 0;
static int get staticMember => 0;
static void set staticMember(int value) {}
static void set staticMember2(int? value) {}
static void staticMethod() {}
}
void main() {}

View file

@ -0,0 +1,98 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:17:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:18:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:19:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember = 42;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:21:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember.isEven;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:22:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember.toString();
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:23:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property[0];
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:24:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property[0] = 0;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:25:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property2[0] ??= 0;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:26:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember2 ??= 42;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:27:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember += 2;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:28:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember++;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:29:5: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// --C?.staticMember;
// ^
//
import self as self;
import "dart:core" as core;
class C extends core::Object {
synthetic constructor •() → self::C
: super core::Object::•()
;
static get staticMember() → core::int
return 0;
static set staticMember(core::int value) → void {}
static get staticMember2() → core::int?
return 0;
static set staticMember2(core::int? value) → void {}
static method staticMethod() → void {}
static get property() → core::List<core::int>
return <core::int>[0];
static get property2() → core::Map<core::int, core::int?>
return <core::int, core::int?>{};
}
static method main() → void {
self::C::staticMember;
self::C::staticMember;
self::C::staticMember = 42;
self::C::staticMethod();
self::C::staticMember.{core::int::isEven};
self::C::staticMember.{core::int::toString}();
self::C::property.{core::List::[]}(0);
self::C::property.{core::List::[]=}(0, 0);
let final core::Map<core::int, core::int?> #t1 = self::C::property2 in let final core::int #t2 = 0 in #t1.{core::Map::[]}(#t2).{core::num::==}(null) ?{core::int} #t1.{core::Map::[]=}(#t2, 0) : null;
self::C::staticMember2.{core::num::==}(null) ?{core::int} self::C::staticMember2 = 42 : null;
self::C::staticMember = self::C::staticMember.{core::num::+}(2);
self::C::staticMember = self::C::staticMember.{core::num::+}(1);
self::C::staticMember = self::C::staticMember.{core::num::-}(1);
}

View file

@ -0,0 +1,104 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:17:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:18:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:19:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember = 42;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:21:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember.isEven;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:22:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember.toString();
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:23:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property[0];
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:24:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property[0] = 0;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:25:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.property2[0] ??= 0;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:26:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember2 ??= 42;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:27:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember += 2;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:28:3: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// C?.staticMember++;
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_static_access.dart:29:5: Warning: The class 'C' cannot be null.
// Try replacing '?.' with '.'
// --C?.staticMember;
// ^
//
import self as self;
import "dart:core" as core;
class C extends core::Object {
synthetic constructor •() → self::C
: super core::Object::•()
;
static get staticMember() → core::int
return 0;
static set staticMember(core::int value) → void {}
static get staticMember2() → core::int?
return 0;
static set staticMember2(core::int? value) → void {}
static method staticMethod() → void {}
static get property() → core::List<core::int>
return <core::int>[0];
static get property2() → core::Map<core::int, core::int?>
return <core::int, core::int?>{};
}
static method main() → void {
self::C::staticMember;
self::C::staticMember;
self::C::staticMember = 42;
self::C::staticMethod();
self::C::staticMember.{core::int::isEven};
self::C::staticMember.{core::int::toString}();
self::C::property.{core::List::[]}(0);
self::C::property.{core::List::[]=}(0, 0);
let final core::Map<core::int, core::int?> #t1 = self::C::property2 in let final core::int #t2 = 0 in #t1.{core::Map::[]}(#t2).{core::num::==}(null) ?{core::int} #t1.{core::Map::[]=}(#t2, 0) : null;
self::C::staticMember2.{core::num::==}(null) ?{core::int} self::C::staticMember2 = 42 : null;
self::C::staticMember = self::C::staticMember.{core::num::+}(2);
self::C::staticMember = self::C::staticMember.{core::num::+}(1);
self::C::staticMember = self::C::staticMember.{core::num::-}(1);
}
Extra constant evaluation status:
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_static_access.dart:25:16 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_static_access.dart:25:16 -> IntConstant(0)
Extra constant evaluation: evaluated: 38, effectively constant: 2

View file

@ -0,0 +1,57 @@
// 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.
class C {
int? m1;
int m2 = 0;
C get property => this;
test() {
this?.m1;
this?.m1 = 42;
this?.method();
this?.property.m1;
this?.property.method();
this?[0];
this?[0] = 0;
this?[0] ??= 0;
this?.property[0];
this?.property[0] = 0;
this?.property[0] ??= 0;
this?.m1 ??= 42;
this?.m2 += 2;
this?.m2++;
--this?.m2;
this ?? new C();
}
int? operator [](int index) => 0;
void operator []=(int index, int value) {}
method() {}
}
class D {
D get property => this;
test() {
this?[0];
this?[0] = 0;
this?[0] += 0;
this?.property[0];
this?.property[0] = 0;
this?.property[0] += 0;
}
int operator [](int index) => 0;
void operator []=(int index, int value) {}
}
main() {
new C().test();
new D().test();
}

View file

@ -0,0 +1,34 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class C extends core::Object {
field core::int? m1;
field core::int m2;
synthetic constructor •() → self::C
;
get property() → self::C
;
method test() → dynamic
;
operator [](core::int index) → core::int?
;
operator []=(core::int index, core::int value) → void
;
method method() → dynamic
;
}
class D extends core::Object {
synthetic constructor •() → self::D
;
get property() → self::D
;
method test() → dynamic
;
operator [](core::int index) → core::int
;
operator []=(core::int index, core::int value) → void
;
}
static method main() → dynamic
;

View file

@ -0,0 +1,170 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:12:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:13:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1 = 42;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:14:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.method();
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:15:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property.m1;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:16:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property.method();
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:17:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:18:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:19:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] ??= 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:20:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:21:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:22:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] ??= 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:23:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1 ??= 42;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:24:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m2 += 2;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:25:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m2++;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:26:7: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// --this?.m2;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:27:5: Warning: Operand of null-aware operation '??' has type 'C' which excludes null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/null_aware_this_access.dart'.
// this ?? new C();
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:41:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:42:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:43:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] += 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:44:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:45:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:46:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] += 0;
// ^^^^
//
import self as self;
import "dart:core" as core;
class C extends core::Object {
field core::int? m1 = null;
field core::int m2 = 0;
synthetic constructor •() → self::C
: super core::Object::•()
;
get property() → self::C
return this;
method test() → dynamic {
this.{self::C::m1};
this.{self::C::m1} = 42;
this.{self::C::method}();
this.{self::C::property}.{self::C::m1};
this.{self::C::property}.{self::C::method}();
this.{self::C::[]}(0);
this.{self::C::[]=}(0, 0);
let final core::int #t1 = 0 in this.{self::C::[]}(#t1).{core::num::==}(null) ?{core::int} this.{self::C::[]=}(#t1, 0) : null;
this.{self::C::property}.{self::C::[]}(0);
this.{self::C::property}.{self::C::[]=}(0, 0);
let final self::C #t2 = this.{self::C::property} in let final core::int #t3 = 0 in #t2.{self::C::[]}(#t3).{core::num::==}(null) ?{core::int} #t2.{self::C::[]=}(#t3, 0) : null;
this.{self::C::m1}.{core::num::==}(null) ?{core::int} this.{self::C::m1} = 42 : null;
this.{self::C::m2} = this.{self::C::m2}.{core::num::+}(2);
this.{self::C::m2} = this.{self::C::m2}.{core::num::+}(1);
this.{self::C::m2} = this.{self::C::m2}.{core::num::-}(1);
this;
}
operator [](core::int index) → core::int?
return 0;
operator []=(core::int index, core::int value) → void {}
method method() → dynamic {}
}
class D extends core::Object {
synthetic constructor •() → self::D
: super core::Object::•()
;
get property() → self::D
return this;
method test() → dynamic {
this.{self::D::[]}(0);
this.{self::D::[]=}(0, 0);
let final core::int #t4 = 0 in this.{self::D::[]=}(#t4, this.{self::D::[]}(#t4).{core::num::+}(0));
this.{self::D::property}.{self::D::[]}(0);
this.{self::D::property}.{self::D::[]=}(0, 0);
let final self::D #t5 = this.{self::D::property} in let final core::int #t6 = 0 in #t5.{self::D::[]=}(#t6, #t5.{self::D::[]}(#t6).{core::num::+}(0));
}
operator [](core::int index) → core::int
return 0;
operator []=(core::int index, core::int value) → void {}
}
static method main() → dynamic {
new self::C::•().{self::C::test}();
new self::D::•().{self::D::test}();
}

View file

@ -0,0 +1,182 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:12:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:13:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1 = 42;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:14:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.method();
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:15:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property.m1;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:16:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property.method();
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:17:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:18:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:19:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] ??= 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:20:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:21:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:22:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] ??= 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:23:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1 ??= 42;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:24:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m2 += 2;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:25:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m2++;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:26:7: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// --this?.m2;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:27:5: Warning: Operand of null-aware operation '??' has type 'C' which excludes null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/null_aware_this_access.dart'.
// this ?? new C();
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:41:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:42:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:43:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] += 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:44:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:45:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:46:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] += 0;
// ^^^^
//
import self as self;
import "dart:core" as core;
class C extends core::Object {
field core::int? m1 = null;
field core::int m2 = 0;
synthetic constructor •() → self::C
: super core::Object::•()
;
get property() → self::C
return this;
method test() → dynamic {
this.{self::C::m1};
this.{self::C::m1} = 42;
this.{self::C::method}();
this.{self::C::property}.{self::C::m1};
this.{self::C::property}.{self::C::method}();
this.{self::C::[]}(0);
this.{self::C::[]=}(0, 0);
let final core::int #t1 = 0 in this.{self::C::[]}(#t1).{core::num::==}(null) ?{core::int} this.{self::C::[]=}(#t1, 0) : null;
this.{self::C::property}.{self::C::[]}(0);
this.{self::C::property}.{self::C::[]=}(0, 0);
let final self::C #t2 = this.{self::C::property} in let final core::int #t3 = 0 in #t2.{self::C::[]}(#t3).{core::num::==}(null) ?{core::int} #t2.{self::C::[]=}(#t3, 0) : null;
this.{self::C::m1}.{core::num::==}(null) ?{core::int} this.{self::C::m1} = 42 : null;
this.{self::C::m2} = this.{self::C::m2}.{core::num::+}(2);
this.{self::C::m2} = this.{self::C::m2}.{core::num::+}(1);
this.{self::C::m2} = this.{self::C::m2}.{core::num::-}(1);
this;
}
operator [](core::int index) → core::int?
return 0;
operator []=(core::int index, core::int value) → void {}
method method() → dynamic {}
}
class D extends core::Object {
synthetic constructor •() → self::D
: super core::Object::•()
;
get property() → self::D
return this;
method test() → dynamic {
this.{self::D::[]}(0);
this.{self::D::[]=}(0, 0);
let final core::int #t4 = 0 in this.{self::D::[]=}(#t4, this.{self::D::[]}(#t4).{core::num::+}(0));
this.{self::D::property}.{self::D::[]}(0);
this.{self::D::property}.{self::D::[]=}(0, 0);
let final self::D #t5 = this.{self::D::property} in let final core::int #t6 = 0 in #t5.{self::D::[]=}(#t6, #t5.{self::D::[]}(#t6).{core::num::+}(0));
}
operator [](core::int index) → core::int
return 0;
operator []=(core::int index, core::int value) → void {}
}
static method main() → dynamic {
new self::C::•().{self::C::test}();
new self::D::•().{self::D::test}();
}
Extra constant evaluation status:
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:19:11 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:19:11 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:22:20 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:22:20 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:43:11 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:43:11 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:46:20 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:46:20 -> IntConstant(0)
Extra constant evaluation: evaluated: 100, effectively constant: 8

View file

@ -0,0 +1,18 @@
class C {
int? m1;
int m2 = 0;
C get property => this;
test() {}
int? operator [](int index) => 0;
void operator []=(int index, int value) {}
method() {}
}
class D {
D get property => this;
test() {}
int operator [](int index) => 0;
void operator []=(int index, int value) {}
}
main() {}

View file

@ -0,0 +1,18 @@
class C {
C get property => this;
int? m1;
int? operator [](int index) => 0;
int m2 = 0;
method() {}
test() {}
void operator []=(int index, int value) {}
}
class D {
D get property => this;
int operator [](int index) => 0;
test() {}
void operator []=(int index, int value) {}
}
main() {}

View file

@ -0,0 +1,170 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:12:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:13:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1 = 42;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:14:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.method();
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:15:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property.m1;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:16:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property.method();
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:17:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:18:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:19:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] ??= 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:20:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:21:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:22:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] ??= 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:23:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1 ??= 42;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:24:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m2 += 2;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:25:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m2++;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:26:7: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// --this?.m2;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:27:5: Warning: Operand of null-aware operation '??' has type 'C' which excludes null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/null_aware_this_access.dart'.
// this ?? new C();
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:41:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:42:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:43:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] += 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:44:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:45:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:46:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] += 0;
// ^^^^
//
import self as self;
import "dart:core" as core;
class C extends core::Object {
field core::int? m1 = null;
field core::int m2 = 0;
synthetic constructor •() → self::C
: super core::Object::•()
;
get property() → self::C
return this;
method test() → dynamic {
this.{self::C::m1};
this.{self::C::m1} = 42;
this.{self::C::method}();
this.{self::C::property}.{self::C::m1};
this.{self::C::property}.{self::C::method}();
this.{self::C::[]}(0);
this.{self::C::[]=}(0, 0);
let final core::int #t1 = 0 in this.{self::C::[]}(#t1).{core::num::==}(null) ?{core::int} this.{self::C::[]=}(#t1, 0) : null;
this.{self::C::property}.{self::C::[]}(0);
this.{self::C::property}.{self::C::[]=}(0, 0);
let final self::C #t2 = this.{self::C::property} in let final core::int #t3 = 0 in #t2.{self::C::[]}(#t3).{core::num::==}(null) ?{core::int} #t2.{self::C::[]=}(#t3, 0) : null;
this.{self::C::m1}.{core::num::==}(null) ?{core::int} this.{self::C::m1} = 42 : null;
this.{self::C::m2} = this.{self::C::m2}.{core::num::+}(2);
this.{self::C::m2} = this.{self::C::m2}.{core::num::+}(1);
this.{self::C::m2} = this.{self::C::m2}.{core::num::-}(1);
this;
}
operator [](core::int index) → core::int?
return 0;
operator []=(core::int index, core::int value) → void {}
method method() → dynamic {}
}
class D extends core::Object {
synthetic constructor •() → self::D
: super core::Object::•()
;
get property() → self::D
return this;
method test() → dynamic {
this.{self::D::[]}(0);
this.{self::D::[]=}(0, 0);
let final core::int #t4 = 0 in this.{self::D::[]=}(#t4, this.{self::D::[]}(#t4).{core::num::+}(0));
this.{self::D::property}.{self::D::[]}(0);
this.{self::D::property}.{self::D::[]=}(0, 0);
let final self::D #t5 = this.{self::D::property} in let final core::int #t6 = 0 in #t5.{self::D::[]=}(#t6, #t5.{self::D::[]}(#t6).{core::num::+}(0));
}
operator [](core::int index) → core::int
return 0;
operator []=(core::int index, core::int value) → void {}
}
static method main() → dynamic {
new self::C::•().{self::C::test}();
new self::D::•().{self::D::test}();
}

View file

@ -0,0 +1,182 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:12:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:13:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1 = 42;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:14:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.method();
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:15:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property.m1;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:16:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property.method();
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:17:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:18:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:19:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] ??= 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:20:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:21:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:22:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] ??= 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:23:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m1 ??= 42;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:24:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m2 += 2;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:25:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.m2++;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:26:7: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// --this?.m2;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:27:5: Warning: Operand of null-aware operation '??' has type 'C' which excludes null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/null_aware_this_access.dart'.
// this ?? new C();
// ^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:41:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:42:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:43:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?[0] += 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:44:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0];
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:45:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] = 0;
// ^^^^
//
// pkg/front_end/testcases/nnbd/null_aware_this_access.dart:46:5: Warning: The receiver 'this' cannot be null.
// Try replacing '?.' with '.'
// this?.property[0] += 0;
// ^^^^
//
import self as self;
import "dart:core" as core;
class C extends core::Object {
field core::int? m1 = null;
field core::int m2 = 0;
synthetic constructor •() → self::C
: super core::Object::•()
;
get property() → self::C
return this;
method test() → dynamic {
this.{self::C::m1};
this.{self::C::m1} = 42;
this.{self::C::method}();
this.{self::C::property}.{self::C::m1};
this.{self::C::property}.{self::C::method}();
this.{self::C::[]}(0);
this.{self::C::[]=}(0, 0);
let final core::int #t1 = 0 in this.{self::C::[]}(#t1).{core::num::==}(null) ?{core::int} this.{self::C::[]=}(#t1, 0) : null;
this.{self::C::property}.{self::C::[]}(0);
this.{self::C::property}.{self::C::[]=}(0, 0);
let final self::C #t2 = this.{self::C::property} in let final core::int #t3 = 0 in #t2.{self::C::[]}(#t3).{core::num::==}(null) ?{core::int} #t2.{self::C::[]=}(#t3, 0) : null;
this.{self::C::m1}.{core::num::==}(null) ?{core::int} this.{self::C::m1} = 42 : null;
this.{self::C::m2} = this.{self::C::m2}.{core::num::+}(2);
this.{self::C::m2} = this.{self::C::m2}.{core::num::+}(1);
this.{self::C::m2} = this.{self::C::m2}.{core::num::-}(1);
this;
}
operator [](core::int index) → core::int?
return 0;
operator []=(core::int index, core::int value) → void {}
method method() → dynamic {}
}
class D extends core::Object {
synthetic constructor •() → self::D
: super core::Object::•()
;
get property() → self::D
return this;
method test() → dynamic {
this.{self::D::[]}(0);
this.{self::D::[]=}(0, 0);
let final core::int #t4 = 0 in this.{self::D::[]=}(#t4, this.{self::D::[]}(#t4).{core::num::+}(0));
this.{self::D::property}.{self::D::[]}(0);
this.{self::D::property}.{self::D::[]=}(0, 0);
let final self::D #t5 = this.{self::D::property} in let final core::int #t6 = 0 in #t5.{self::D::[]=}(#t6, #t5.{self::D::[]}(#t6).{core::num::+}(0));
}
operator [](core::int index) → core::int
return 0;
operator []=(core::int index, core::int value) → void {}
}
static method main() → dynamic {
new self::C::•().{self::C::test}();
new self::D::•().{self::D::test}();
}
Extra constant evaluation status:
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:19:11 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:19:11 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:22:20 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:22:20 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:43:11 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:43:11 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:46:20 -> IntConstant(0)
Evaluated: VariableGet @ org-dartlang-testcase:///null_aware_this_access.dart:46:20 -> IntConstant(0)
Extra constant evaluation: evaluated: 100, effectively constant: 8

View file

@ -258,7 +258,7 @@ class VMService extends MessageRouter {
}
acceptNewWebSocketConnections(false);
_ddsUri = Uri.parse(uri);
await VMServiceEmbedderHooks?.ddsConnected!();
await VMServiceEmbedderHooks.ddsConnected!();
return encodeSuccess(message);
}

View file

@ -118,8 +118,10 @@ class C {
void instanceTest() {
// v ??= e is equivalent to ((x) => x == null ? v = e : x)(v)
vGetValue = 1; check(1, () => v ??= bad(), ['$s.v']);
yGetValue = 1; check(1, () => v ??= y, ['$s.v', 'y', '$s.v=1']);
vGetValue = 1;
check(1, () => v ??= bad(), ['$s.v']);
yGetValue = 1;
check(1, () => v ??= y, ['$s.v', 'y', '$s.v=1']);
finalOne ??= null;
// ^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL
@ -144,8 +146,10 @@ class D extends C {
void derivedInstanceTest() {
// super.v ??= e is equivalent to
// ((x) => x == null ? super.v = e : x)(super.v)
vGetValue = 1; check(1, () => super.v ??= bad(), ['$s.v']);
yGetValue = 1; check(1, () => super.v ??= y, ['$s.v', 'y', '$s.v=1']);
vGetValue = 1;
check(1, () => super.v ??= bad(), ['$s.v']);
yGetValue = 1;
check(1, () => super.v ??= y, ['$s.v', 'y', '$s.v=1']);
}
}
@ -159,26 +163,41 @@ main() {
new D('d').derivedInstanceTest();
// v ??= e is equivalent to ((x) => x == null ? v = e : x)(v)
xGetValue = 1; check(1, () => x ??= bad(), ['x']);
yGetValue = 1; check(1, () => x ??= y, ['x', 'y', 'x=1']);
h.xGetValue = 1; check(1, () => h.x ??= bad(), ['h.x']);
yGetValue = 1; check(1, () => h.x ??= y, ['h.x', 'y', 'h.x=1']);
{ var l = 1; check(1, () => l ??= bad(), []); }
// ^
// [cfe] Operand of null-aware operation '??=' has type 'int' which excludes null.
// ^^^^^
// [analyzer] STATIC_WARNING.DEAD_NULL_AWARE_EXPRESSION
{ var l; yGetValue = 1; check(1, () => l ??= y, ['y']); Expect.equals(1, l); }
{ final l = 1; l ??= null; }
// ^
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_LOCAL
// [cfe] Can't assign to the final variable 'l'.
// ^
// [cfe] Operand of null-aware operation '??=' has type 'int' which excludes null.
// ^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^^^^
// [analyzer] STATIC_WARNING.DEAD_NULL_AWARE_EXPRESSION
xGetValue = 1;
check(1, () => x ??= bad(), ['x']);
yGetValue = 1;
check(1, () => x ??= y, ['x', 'y', 'x=1']);
h.xGetValue = 1;
check(1, () => h.x ??= bad(), ['h.x']);
yGetValue = 1;
check(1, () => h.x ??= y, ['h.x', 'y', 'h.x=1']);
{
var l = 1;
check(1, () => l ??= bad(), []);
// ^
// [cfe] Operand of null-aware operation '??=' has type 'int' which excludes null.
// ^^^^^
// [analyzer] STATIC_WARNING.DEAD_NULL_AWARE_EXPRESSION
}
{
var l;
yGetValue = 1;
check(1, () => l ??= y, ['y']);
Expect.equals(1, l);
}
{
final l = 1;
l ??= null;
// ^
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_LOCAL
// [cfe] Can't assign to the final variable 'l'.
// ^
// [cfe] Operand of null-aware operation '??=' has type 'int' which excludes null.
// ^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^^^^
// [analyzer] STATIC_WARNING.DEAD_NULL_AWARE_EXPRESSION
}
C ??= null;
//^
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_TYPE
@ -195,39 +214,55 @@ main() {
// [cfe] A prefix can't be used as an expression.
// C.v ??= e is equivalent to ((x) => x == null ? C.v = e : x)(C.v)
C.xGetValue = 1; check(1, () => C.x ??= bad(), ['C.x']);
yGetValue = 1; check(1, () => C.x ??= y, ['C.x', 'y', 'C.x=1']);
h.C.xGetValue = 1; check(1, () => h.C.x ??= bad(), ['h.C.x']);
yGetValue = 1; check(1, () => h.C.x ??= y, ['h.C.x', 'y', 'h.C.x=1']);
C.xGetValue = 1;
check(1, () => C.x ??= bad(), ['C.x']);
yGetValue = 1;
check(1, () => C.x ??= y, ['C.x', 'y', 'C.x=1']);
h.C.xGetValue = 1;
check(1, () => h.C.x ??= bad(), ['h.C.x']);
yGetValue = 1;
check(1, () => h.C.x ??= y, ['h.C.x', 'y', 'h.C.x=1']);
// e1.v ??= e2 is equivalent to
// ((x) => ((y) => y == null ? x.v = e2 : y)(x.v))(e1)
xGetValue = new C('x'); xGetValue.vGetValue = 1;
xGetValue = new C('x');
xGetValue.vGetValue = 1;
check(1, () => x.v ??= bad(), ['x', 'x.v']);
xGetValue = new C('x'); yGetValue = 1;
xGetValue = new C('x');
yGetValue = 1;
check(1, () => x.v ??= y, ['x', 'x.v', 'y', 'x.v=1']);
fValue = new C('f()'); fValue.vGetValue = 1;
fValue = new C('f()');
fValue.vGetValue = 1;
check(1, () => f().v ??= bad(), ['f()', 'f().v']);
fValue = new C('f()'); yGetValue = 1;
fValue = new C('f()');
yGetValue = 1;
check(1, () => f().v ??= y, ['f()', 'f().v', 'y', 'f().v=1']);
// e1[e2] ??= e3 is equivalent to
// ((a, i) => ((x) => x == null ? a[i] = e3 : x)(a[i]))(e1, e2)
xGetValue = new C('x'); yGetValue = 1; xGetValue.indexGetValue = 2;
xGetValue = new C('x');
yGetValue = 1;
xGetValue.indexGetValue = 2;
check(2, () => x[y] ??= bad(), ['x', 'y', 'x[1]']);
xGetValue = new C('x'); yGetValue = 1; zGetValue = 2;
xGetValue = new C('x');
yGetValue = 1;
zGetValue = 2;
check(2, () => x[y] ??= z, ['x', 'y', 'x[1]', 'z', 'x[1]=2']);
// e1?.v ??= e2 is equivalent to ((x) => x == null ? null : x.v ??= e2)(e1).
check(null, () => x?.v ??= bad(), ['x']);
xGetValue = new C('x'); xGetValue.vGetValue = 1;
xGetValue = new C('x');
xGetValue.vGetValue = 1;
check(1, () => x?.v ??= bad(), ['x', 'x.v']);
xGetValue = new C('x'); yGetValue = 1;
xGetValue = new C('x');
yGetValue = 1;
check(1, () => x?.v ??= y, ['x', 'x.v', 'y', 'x.v=1']);
// C?.v ??= e2 is equivalent to C.v ??= e2.
C.xGetValue = 1;
check(1, () => C?.x ??= bad(), ['C.x']);
// ^
// [cfe] The class 'C' cannot be null.
h.C.xgetValue = 1;
// ^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_SETTER
@ -238,6 +273,10 @@ main() {
// [cfe] Getter not found: 'c'.
yGetValue = 1;
check(1, () => C?.x ??= y, ['C.x', 'y', 'C.x=1']);
// ^
// [cfe] The class 'C' cannot be null.
yGetValue = 1;
check(1, () => h.C?.x ??= y, ['h.C.x', 'y', 'h.C.x=1']);
// ^
// [cfe] The class 'C' cannot be null.
}

View file

@ -32,36 +32,75 @@ main() {
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
// C?.id is equivalent to C.id.
{ C.staticInt = 1; Expect.equals(1, C?.staticInt); }
{ h.C.staticInt = 1; Expect.equals(1, h.C?.staticInt); }
{
C.staticInt = 1;
Expect.equals(1, C?.staticInt);
// ^
// [cfe] The class 'C' cannot be null.
}
{
h.C.staticInt = 1;
Expect.equals(1, h.C?.staticInt);
// ^
// [cfe] The class 'C' cannot be null.
}
// The static type of e1?.d is the static type of e1.id.
{ int? i = new C(1)?.v; Expect.equals(1, i); }
// ^
// [cfe] Operand of null-aware operation '?.' has type 'C' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
{ String? s = new C(null)?.v; Expect.equals(null, s); }
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'int?' can't be assigned to a variable of type 'String?'.
// ^
// [cfe] Operand of null-aware operation '?.' has type 'C' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
{ C.staticInt = 1; int? i = C?.staticInt; Expect.equals(1, i); }
{ h.C.staticInt = 1; int? i = h.C?.staticInt; Expect.equals(1, i); }
{ C.staticInt = null; String? s = C?.staticInt; Expect.equals(null, s); }
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'int?' can't be assigned to a variable of type 'String?'.
{ h.C.staticNullable = null; String? s = h.C?.staticNullable; Expect.equals(null, s); }
// ^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'int?' can't be assigned to a variable of type 'String?'.
{
int? i = new C(1)?.v;
// ^
// [cfe] Operand of null-aware operation '?.' has type 'C' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
Expect.equals(1, i);
}
{
String? s = new C(null)?.v;
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'int?' can't be assigned to a variable of type 'String?'.
// ^
// [cfe] Operand of null-aware operation '?.' has type 'C' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
Expect.equals(null, s);
}
{
C.staticInt = 1;
int? i = C?.staticInt;
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(1, i);
}
{
h.C.staticInt = 1;
int? i = h.C?.staticInt;
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(1, i);
}
{
C.staticInt = null;
String? s = C?.staticInt;
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] The class 'C' cannot be null.
// ^
// [cfe] A value of type 'int?' can't be assigned to a variable of type 'String?'.
Expect.equals(null, s);
}
{
h.C.staticNullable = null;
String? s = h.C?.staticNullable;
// ^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] The class 'C' cannot be null.
// ^
// [cfe] A value of type 'int?' can't be assigned to a variable of type 'String?'.
Expect.equals(null, s);
}
// Let T be the static type of e1 and let y be a fresh variable of type T.
// Exactly the same static warnings that would be caused by y.id are also
@ -70,10 +109,13 @@ main() {
// ^^^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
// [cfe] The getter 'bad' isn't defined for the class 'C'.
{ var b = new C(1) as B?; Expect.equals(1, b?.v); }
// ^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
// [cfe] The getter 'v' isn't defined for the class 'B'.
{
var b = new C(1) as B?;
Expect.equals(1, b?.v);
// ^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
// [cfe] The getter 'v' isn't defined for the class 'B'.
}
// '?.' cannot be used to access toplevel properties in libraries imported via
// prefix.

View file

@ -48,34 +48,84 @@ main() {
// e1?.v = e2 is equivalent to ((x) => x == null ? null : x.v = e2)(e1).
Expect.equals(null, nullC()?.v = bad());
{ C c = new C(1); Expect.equals(2, c?.v = 2); Expect.equals(2, c.v); }
// ^
// [cfe] Operand of null-aware operation '?.' has type 'C' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
{
C c = new C(1);
Expect.equals(2, c?.v = 2);
// ^
// [cfe] Operand of null-aware operation '?.' has type 'C' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
Expect.equals(2, c.v);
}
// C?.v = e2 is equivalent to C.v = e2.
{ C.staticInt = 1; Expect.equals(2, C?.staticInt = 2); Expect.equals(2, C.staticInt); }
{ h.C.staticInt = 1; Expect.equals(2, h.C?.staticInt = 2); Expect.equals(2, h.C.staticInt); }
{
C.staticInt = 1;
Expect.equals(2, C?.staticInt = 2);
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(2, C.staticInt);
}
{
h.C.staticInt = 1;
Expect.equals(2, h.C?.staticInt = 2);
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(2, h.C.staticInt);
}
// The static type of e1?.v = e2 is the static type of e2.
{ var d = new D(new E()) as D?; G g = new G(); F? f = (d?.v = g); Expect.identical(f, g); }
{ var d = new D(new E()) as D?; E e = new G(); F? f = (d?.v = e); }
// ^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] A value of type 'E?' can't be assigned to a variable of type 'F?'.
{ D.staticE = new E(); G g = new G(); F? f = (D?.staticE = g); Expect.identical(f, g); }
{ h.D.staticE = new h.E(); h.G g = new h.G(); h.F? f = (h.D?.staticE = g); Expect.identical(f, g); }
{ D.staticE = new E(); E e = new G(); F? f = (D?.staticE = e); }
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F?'.
{ h.D.staticE = new h.E(); h.E e = new h.G(); h.F f = (h.D?.staticE = e); }
// ^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F'.
{
var d = new D(new E()) as D?;
G g = new G();
F? f = (d?.v = g);
Expect.identical(f, g);
}
{
var d = new D(new E()) as D?;
E e = new G();
F? f = (d?.v = e);
// ^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] A value of type 'E?' can't be assigned to a variable of type 'F?'.
}
{
D.staticE = new E();
G g = new G();
F? f = (D?.staticE = g);
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(f, g);
}
{
h.D.staticE = new h.E();
h.G g = new h.G();
h.F? f = (h.D?.staticE = g);
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(f, g);
}
{
D.staticE = new E();
E e = new G();
F? f = (D?.staticE = e);
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F?'.
}
{
h.D.staticE = new h.E();
h.E e = new h.G();
h.F f = (h.D?.staticE = e);
// ^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F'.
}
// Exactly the same errors that would be caused by e1.v = e2 are
// also generated in the case of e1?.v = e2.
@ -83,34 +133,65 @@ main() {
// ^^^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_SETTER
// [cfe] The setter 'bad' isn't defined for the class 'C'.
{ B b = new C(1); Expect.equals(2, b?.v = 2); }
// ^
// [cfe] Operand of null-aware operation '?.' has type 'B' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
// ^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_SETTER
// [cfe] The setter 'v' isn't defined for the class 'B'.
{
B b = new C(1);
Expect.equals(2, b?.v = 2);
// ^
// [cfe] Operand of null-aware operation '?.' has type 'B' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
// ^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_SETTER
// [cfe] The setter 'v' isn't defined for the class 'B'.
}
// e1?.v op= e2 is equivalent to ((x) => x?.v = x.v op e2)(e1).
Expect.equals(null, nullC()?.v += bad());
{ C c = new C(1); Expect.equals(3, c?.v += 2); Expect.equals(3, c.v); }
// ^
// [cfe] Operand of null-aware operation '?.' has type 'C' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
{
C c = new C(1);
Expect.equals(3, c?.v += 2);
// ^
// [cfe] Operand of null-aware operation '?.' has type 'C' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
Expect.equals(3, c.v);
}
// C?.v op= e2 is equivalent to C.v op= e2.
{ C.staticInt = 1; Expect.equals(3, C?.staticInt += 2); Expect.equals(3, C?.staticInt); }
{
C.staticInt = 1;
Expect.equals(3, C?.staticInt += 2);
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(3, C?.staticInt);
// ^
// [cfe] The class 'C' cannot be null.
}
// The static type of e1?.v op= e2 is the static type of e1.v op e2.
{ D d = new D(new E()); F? f = (d?.v += 1); Expect.identical(d.v, f); }
// ^
// [cfe] Operand of null-aware operation '?.' has type 'D' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
{ D.staticE = new E(); F? f = (D?.staticE += 1); Expect.identical(D.staticE, f); }
{ h.D.staticE = new h.E(); h.F? f = (h.D?.staticE += 1); Expect.identical(h.D.staticE, f); }
{
D d = new D(new E());
F? f = (d?.v += 1);
// ^
// [cfe] Operand of null-aware operation '?.' has type 'D' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
Expect.identical(d.v, f);
}
{
D.staticE = new E();
F? f = (D?.staticE += 1);
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(D.staticE, f);
}
{
h.D.staticE = new h.E();
h.F? f = (h.D?.staticE += 1);
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(h.D.staticE, f);
}
// Let T be the static type of e1 and let y be a fresh variable of type T.
// Exactly the same errors that would be caused by y.v op e2 are
@ -119,51 +200,79 @@ main() {
// ^^^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_SETTER
// [cfe] The setter 'bad' isn't defined for the class 'C'.
{ B b = new C(1); b?.v += 2; }
// ^
// [cfe] Operand of null-aware operation '?.' has type 'B' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
// ^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
// [cfe] The getter 'v' isn't defined for the class 'B'.
// ^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_SETTER
// [cfe] The setter 'v' isn't defined for the class 'B'.
{ D d = new D(new E()); F? f = (d?.v += nullC()); }
// ^
// [cfe] Operand of null-aware operation '?.' has type 'D' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
// ^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// [cfe] A value of type 'C?' can't be assigned to a variable of type 'int'.
{ D d = new D(new E()); H? h = (d?.v += 1); }
// ^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] A value of type 'G?' can't be assigned to a variable of type 'H?'.
// ^
// [cfe] Operand of null-aware operation '?.' has type 'D' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
{ D.staticE = new E(); F? f = (D?.staticE += nullC()); }
// ^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// [cfe] A value of type 'C?' can't be assigned to a variable of type 'int'.
{ h.D.staticE = new h.E(); h.F? f = (h.D?.staticE += h.nullC()); }
// ^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// [cfe] A value of type 'C?' can't be assigned to a variable of type 'int'.
{ D.staticE = new E(); H? h = (D?.staticE += 1); }
// ^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
{ h.D.staticE = new h.E(); h.H? hh = (h.D?.staticE += 1); }
// ^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
{
B b = new C(1);
b?.v += 2;
// ^
// [cfe] Operand of null-aware operation '?.' has type 'B' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
// ^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
// [cfe] The getter 'v' isn't defined for the class 'B'.
// ^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_SETTER
// [cfe] The setter 'v' isn't defined for the class 'B'.
}
{
D d = new D(new E());
F? f = (d?.v += nullC());
// ^
// [cfe] Operand of null-aware operation '?.' has type 'D' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
// ^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// [cfe] A value of type 'C?' can't be assigned to a variable of type 'int'.
}
{
D d = new D(new E());
H? h = (d?.v += 1);
// ^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] A value of type 'G?' can't be assigned to a variable of type 'H?'.
// ^
// [cfe] Operand of null-aware operation '?.' has type 'D' which excludes null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
}
{
D.staticE = new E();
F? f = (D?.staticE += nullC());
// ^
// [cfe] The class 'D' cannot be null.
// ^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// [cfe] A value of type 'C?' can't be assigned to a variable of type 'int'.
}
{
h.D.staticE = new h.E();
h.F? f = (h.D?.staticE += h.nullC());
// ^
// [cfe] The class 'D' cannot be null.
// ^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// [cfe] A value of type 'C?' can't be assigned to a variable of type 'int'.
}
{
D.staticE = new E();
H? h = (D?.staticE += 1);
// ^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
}
{
h.D.staticE = new h.E();
h.H? hh = (h.D?.staticE += 1);
// ^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
}
// '?.' cannot be used to assign to toplevel properties in libraries imported
// via prefix.

View file

@ -42,111 +42,313 @@ main() {
// e1?.v++ is equivalent to ((x) => x == null ? null : x.v++)(e1).
Expect.equals(null, nullC()?.v++);
{ var c = new C(1) as C?; Expect.equals(1, c?.v++); Expect.equals(2, c!.v); }
{
var c = new C(1) as C?;
Expect.equals(1, c?.v++);
Expect.equals(2, c!.v);
}
// C?.v++ is equivalent to C.v++.
{ C.staticInt = 1; Expect.equals(1, C?.staticInt++); Expect.equals(2, C.staticInt); }
{ h.C.staticInt = 1; Expect.equals(1, h.C?.staticInt++); Expect.equals(2, h.C.staticInt); }
{
C.staticInt = 1;
Expect.equals(1, C?.staticInt++);
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(2, C.staticInt);
}
{
h.C.staticInt = 1;
Expect.equals(1, h.C?.staticInt++);
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(2, h.C.staticInt);
}
// The static type of e1?.v++ is the same as the static type of e1.v.
{ E e1 = new E(); var d = new D(e1) as D?; E? e2 = d?.v++; Expect.identical(e1, e2); }
{ G g = new G(); var d = new D(g) as D?; F? f = d?.v++; Expect.identical(f, g); }
// ^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] A value of type 'E?' can't be assigned to a variable of type 'F?'.
{ E e1 = new E(); D.staticE = e1; E? e2 = D?.staticE++; Expect.identical(e1, e2); }
{ h.E e1 = new h.E(); h.D.staticE = e1; h.E? e2 = h.D?.staticE++; Expect.identical(e1, e2); }
{ G g = new G(); D.staticE = g; F? f = D?.staticE++; Expect.identical(f, g); }
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F?'.
{ h.G g = new h.G(); h.D.staticE = g; h.F? f = h.D?.staticE++; Expect.identical(f, g); }
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F?'.
{
E e1 = new E();
var d = new D(e1) as D?;
E? e2 = d?.v++;
Expect.identical(e1, e2);
}
{
G g = new G();
var d = new D(g) as D?;
F? f = d?.v++;
// ^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] A value of type 'E?' can't be assigned to a variable of type 'F?'.
Expect.identical(f, g);
}
{
E e1 = new E();
D.staticE = e1;
E? e2 = D?.staticE++;
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(e1, e2);
}
{
h.E e1 = new h.E();
h.D.staticE = e1;
h.E? e2 = h.D?.staticE++;
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(e1, e2);
}
{
G g = new G();
D.staticE = g;
F? f = D?.staticE++;
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F?'.
Expect.identical(f, g);
}
{
h.G g = new h.G();
h.D.staticE = g;
h.F? f = h.D?.staticE++;
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F?'.
Expect.identical(f, g);
}
// e1?.v-- is equivalent to ((x) => x == null ? null : x.v--)(e1).
Expect.equals(null, nullC()?.v--);
{ var c = new C(1) as C?; Expect.equals(1, c?.v--); Expect.equals(0, c!.v); }
{
var c = new C(1) as C?;
Expect.equals(1, c?.v--);
Expect.equals(0, c!.v);
}
// C?.v-- is equivalent to C.v--.
{ C.staticInt = 1; Expect.equals(1, C?.staticInt--); Expect.equals(0, C.staticInt); }
{ h.C.staticInt = 1; Expect.equals(1, h.C?.staticInt--); Expect.equals(0, h.C.staticInt); }
{
C.staticInt = 1;
Expect.equals(1, C?.staticInt--);
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(0, C.staticInt);
}
{
h.C.staticInt = 1;
Expect.equals(1, h.C?.staticInt--);
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(0, h.C.staticInt);
}
// The static type of e1?.v-- is the same as the static type of e1.v.
{ E e1 = new E(); var d = new D(e1) as D?; E? e2 = d?.v--; Expect.identical(e1, e2); }
{ G g = new G(); var d = new D(g) as D?; F? f = d?.v--; Expect.identical(f, g); }
// ^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] A value of type 'E?' can't be assigned to a variable of type 'F?'.
{ E e1 = new E(); D.staticE = e1; E? e2 = D?.staticE--; Expect.identical(e1, e2); }
{ h.E e1 = new h.E(); h.D.staticE = e1; h.E? e2 = h.D?.staticE--; Expect.identical(e1, e2); }
{ G g = new G(); D.staticE = g; F? f = D?.staticE--; Expect.identical(f, g); }
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F?'.
{ h.G g = new h.G(); h.D.staticE = g; h.F? f = h.D?.staticE--; Expect.identical(f, g); }
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F?'.
{
E e1 = new E();
var d = new D(e1) as D?;
E? e2 = d?.v--;
Expect.identical(e1, e2);
}
{
G g = new G();
var d = new D(g) as D?;
F? f = d?.v--;
// ^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] A value of type 'E?' can't be assigned to a variable of type 'F?'.
Expect.identical(f, g);
}
{
E e1 = new E();
D.staticE = e1;
E? e2 = D?.staticE--;
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(e1, e2);
}
{
h.E e1 = new h.E();
h.D.staticE = e1;
h.E? e2 = h.D?.staticE--;
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(e1, e2);
}
{
G g = new G();
D.staticE = g;
F? f = D?.staticE--;
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F?'.
Expect.identical(f, g);
}
{
h.G g = new h.G();
h.D.staticE = g;
h.F? f = h.D?.staticE--;
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'E' can't be assigned to a variable of type 'F?'.
Expect.identical(f, g);
}
// ++e1?.v is equivalent to e1?.v += 1.
Expect.equals(null, ++nullC()?.v);
{ var c = new C(1) as C?; Expect.equals(2, ++c?.v); Expect.equals(2, c!.v); }
{
var c = new C(1) as C?;
Expect.equals(2, ++c?.v);
Expect.equals(2, c!.v);
}
// ++C?.v is equivalent to C?.v += 1.
{ C.staticInt = 1; Expect.equals(2, ++C?.staticInt); Expect.equals(2, C.staticInt); }
{ h.C.staticInt = 1; Expect.equals(2, ++h.C?.staticInt); Expect.equals(2, h.C.staticInt); }
{
C.staticInt = 1;
Expect.equals(2, ++C?.staticInt);
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(2, C.staticInt);
}
{
h.C.staticInt = 1;
Expect.equals(2, ++h.C?.staticInt);
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(2, h.C.staticInt);
}
// The static type of ++e1?.v is the same as the static type of e1.v + 1.
{ var d = new D(new E()) as D?; F? f = ++d?.v; Expect.identical(d!.v, f); }
{ var d = new D(new E()) as D?; H? h = ++d?.v; Expect.identical(d!.v, h); }
// ^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'G?' can't be assigned to a variable of type 'H?'.
{ D.staticE = new E(); F? f = ++D?.staticE; Expect.identical(D.staticE, f); }
{ h.D.staticE = new h.E(); h.F? f = ++h.D?.staticE; Expect.identical(h.D.staticE, f); }
{ D.staticE = new E(); H? h = ++D?.staticE; Expect.identical(D.staticE, h); }
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
{ h.D.staticE = new h.E(); h.H? hh = ++h.D?.staticE; Expect.identical(h.D.staticE, hh); }
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
{
var d = new D(new E()) as D?;
F? f = ++d?.v;
Expect.identical(d!.v, f);
}
{
var d = new D(new E()) as D?;
H? h = ++d?.v;
// ^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'G?' can't be assigned to a variable of type 'H?'.
Expect.identical(d!.v, h);
}
{
D.staticE = new E();
F? f = ++D?.staticE;
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(D.staticE, f);
}
{
h.D.staticE = new h.E();
h.F? f = ++h.D?.staticE;
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(h.D.staticE, f);
}
{
D.staticE = new E();
H? h = ++D?.staticE;
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
Expect.identical(D.staticE, h);
}
{
h.D.staticE = new h.E();
h.H? hh = ++h.D?.staticE;
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
Expect.identical(h.D.staticE, hh);
}
// --e1?.v is equivalent to e1?.v -= 1.
Expect.equals(null, --nullC()?.v);
{ var c = new C(1) as C?; Expect.equals(0, --c?.v); Expect.equals(0, c!.v); }
{
var c = new C(1) as C?;
Expect.equals(0, --c?.v);
Expect.equals(0, c!.v);
}
// --C?.v is equivalent to C?.v -= 1.
{ C.staticInt = 1; Expect.equals(0, --C?.staticInt); Expect.equals(0, C.staticInt); }
{ h.C.staticInt = 1; Expect.equals(0, --h.C?.staticInt); Expect.equals(0, h.C.staticInt); }
{
C.staticInt = 1;
Expect.equals(0, --C?.staticInt);
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(0, C.staticInt);
}
{
h.C.staticInt = 1;
Expect.equals(0, --h.C?.staticInt);
// ^
// [cfe] The class 'C' cannot be null.
Expect.equals(0, h.C.staticInt);
}
// The static type of --e1?.v is the same as the static type of e1.v - 1.
{ var d = new D(new E()) as D?; F? f = --d?.v; Expect.identical(d!.v, f); }
{ var d = new D(new E()) as D?; H? h = --d?.v; Expect.identical(d!.v, h); }
// ^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'G?' can't be assigned to a variable of type 'H?'.
{ D.staticE = new E(); F? f = --D?.staticE; Expect.identical(D.staticE, f); }
{ h.D.staticE = new h.E(); h.F? f = --h.D?.staticE; Expect.identical(h.D.staticE, f); }
{ D.staticE = new E(); H? h = --D?.staticE; Expect.identical(D.staticE, h); }
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
{ h.D.staticE = new h.E(); h.H? hh = --h.D?.staticE; Expect.identical(h.D.staticE, hh); }
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
{
var d = new D(new E()) as D?;
F? f = --d?.v;
Expect.identical(d!.v, f);
}
{
var d = new D(new E()) as D?;
H? h = --d?.v;
// ^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'G?' can't be assigned to a variable of type 'H?'.
Expect.identical(d!.v, h);
}
{
D.staticE = new E();
F? f = --D?.staticE;
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(D.staticE, f);
}
{
h.D.staticE = new h.E();
h.F? f = --h.D?.staticE;
// ^
// [cfe] The class 'D' cannot be null.
Expect.identical(h.D.staticE, f);
}
{
D.staticE = new E();
H? h = --D?.staticE;
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
Expect.identical(D.staticE, h);
}
{
h.D.staticE = new h.E();
h.H? hh = --h.D?.staticE;
// ^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] The class 'D' cannot be null.
// ^
// [cfe] A value of type 'G' can't be assigned to a variable of type 'H?'.
Expect.identical(h.D.staticE, hh);
}
}

View file

@ -51,15 +51,15 @@ class C extends B {
-super?.field;
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^^
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
// ^^
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
~super?.field;
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^^
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
// ^^
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
!super?.field;
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.NON_BOOL_NEGATION_EXPRESSION
@ -77,26 +77,38 @@ class C extends B {
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
super?.method();
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
1 * super?.method();
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
-super?.method();
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
~super?.method();
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
!super?.method();
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
--super?.method();
//^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
@ -105,6 +117,8 @@ class C extends B {
// ^
// [analyzer] SYNTACTIC_ERROR.MISSING_ASSIGNABLE_SELECTOR
++super?.method();
//^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.

View file

@ -14,21 +14,27 @@ class B {
var field = 1;
method() => 1;
B.forward()
;
B.forward();
test() {
this?.field = 1;
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
this?.field += 1;
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
this?.field;
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
this?.method();
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
}

View file

@ -30,17 +30,25 @@ class B {
test() {
this?.field = 1;
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
this?.field += 1;
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
this?.field;
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
this?.method();
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
// ^
// [cfe] The receiver 'this' cannot be null.
// ^^
// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
}
}