mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:44:27 +00:00
Extension type. Report CONST_EVAL_EXTENSION_TYPE_METHOD if the operator is declared by extension type.
Change-Id: I26a04332939d2a09b898835dc82cdc75cf23fb33 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/347388 Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
a3c115f9b0
commit
7965219df2
7 changed files with 141 additions and 10 deletions
|
@ -415,6 +415,8 @@ CompileTimeErrorCode.CONST_EVAL_ASSERTION_FAILURE:
|
|||
status: needsEvaluation
|
||||
CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD:
|
||||
status: needsEvaluation
|
||||
CompileTimeErrorCode.CONST_EVAL_EXTENSION_TYPE_METHOD:
|
||||
status: needsEvaluation
|
||||
CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT:
|
||||
status: needsEvaluation
|
||||
CompileTimeErrorCode.CONST_EVAL_METHOD_INVOCATION:
|
||||
|
|
|
@ -622,6 +622,8 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
ErrorCode errorCode = error.errorCode;
|
||||
if (identical(
|
||||
errorCode, CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD) ||
|
||||
identical(
|
||||
errorCode, CompileTimeErrorCode.CONST_EVAL_EXTENSION_TYPE_METHOD) ||
|
||||
identical(errorCode, CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT) ||
|
||||
identical(
|
||||
errorCode, CompileTimeErrorCode.CONST_EVAL_METHOD_INVOCATION) ||
|
||||
|
|
|
@ -645,9 +645,19 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
|
||||
@override
|
||||
Constant visitBinaryExpression(BinaryExpression node) {
|
||||
if (node.staticElement?.enclosingElement is ExtensionElement) {
|
||||
return InvalidConstant.forEntity(
|
||||
node, CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD);
|
||||
var operatorElement = node.staticElement;
|
||||
var operatorContainer = operatorElement?.enclosingElement;
|
||||
switch (operatorContainer) {
|
||||
case ExtensionElement():
|
||||
return InvalidConstant.forEntity(
|
||||
node,
|
||||
CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD,
|
||||
);
|
||||
case ExtensionTypeElement():
|
||||
return InvalidConstant.forEntity(
|
||||
node,
|
||||
CompileTimeErrorCode.CONST_EVAL_EXTENSION_TYPE_METHOD,
|
||||
);
|
||||
}
|
||||
|
||||
TokenType operatorType = node.operator.type;
|
||||
|
@ -1148,14 +1158,25 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
|
||||
@override
|
||||
Constant visitPrefixExpression(PrefixExpression node) {
|
||||
var operatorElement = node.staticElement;
|
||||
var operatorContainer = operatorElement?.enclosingElement;
|
||||
switch (operatorContainer) {
|
||||
case ExtensionElement():
|
||||
return InvalidConstant.forEntity(
|
||||
node,
|
||||
CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD,
|
||||
);
|
||||
case ExtensionTypeElement():
|
||||
return InvalidConstant.forEntity(
|
||||
node,
|
||||
CompileTimeErrorCode.CONST_EVAL_EXTENSION_TYPE_METHOD,
|
||||
);
|
||||
}
|
||||
|
||||
var operand = evaluateConstant(node.operand);
|
||||
if (operand is! DartObjectImpl) {
|
||||
return operand;
|
||||
}
|
||||
if (node.staticElement?.enclosingElement is ExtensionElement) {
|
||||
return InvalidConstant.forEntity(
|
||||
node, CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD);
|
||||
}
|
||||
if (node.operator.type == TokenType.BANG) {
|
||||
return _dartObjectComputer.logicalNot(node, operand);
|
||||
} else if (node.operator.type == TokenType.TILDE) {
|
||||
|
@ -1621,9 +1642,19 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
/// an error, and `null` otherwise.
|
||||
Constant? _evaluatePropertyAccess(DartObjectImpl targetResult,
|
||||
SimpleIdentifier identifier, AstNode errorNode) {
|
||||
if (identifier.staticElement?.enclosingElement is ExtensionElement) {
|
||||
return InvalidConstant.forEntity(
|
||||
errorNode, CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD);
|
||||
var propertyElement = identifier.staticElement;
|
||||
var propertyContainer = propertyElement?.enclosingElement;
|
||||
switch (propertyContainer) {
|
||||
case ExtensionElement():
|
||||
return InvalidConstant.forEntity(
|
||||
errorNode,
|
||||
CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD,
|
||||
);
|
||||
case ExtensionTypeElement():
|
||||
return InvalidConstant.forEntity(
|
||||
errorNode,
|
||||
CompileTimeErrorCode.CONST_EVAL_EXTENSION_TYPE_METHOD,
|
||||
);
|
||||
}
|
||||
|
||||
var targetType = targetResult.type;
|
||||
|
|
|
@ -904,6 +904,12 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
|
|||
"Extension methods can't be used in constant expressions.",
|
||||
);
|
||||
|
||||
static const CompileTimeErrorCode CONST_EVAL_EXTENSION_TYPE_METHOD =
|
||||
CompileTimeErrorCode(
|
||||
'CONST_EVAL_EXTENSION_TYPE_METHOD',
|
||||
"Extension type methods can't be used in constant expressions.",
|
||||
);
|
||||
|
||||
static const CompileTimeErrorCode CONST_EVAL_FOR_ELEMENT =
|
||||
CompileTimeErrorCode(
|
||||
'CONST_EVAL_FOR_ELEMENT',
|
||||
|
|
|
@ -122,6 +122,7 @@ const List<ErrorCode> errorCodeValues = [
|
|||
CompileTimeErrorCode.CONST_DEFERRED_CLASS,
|
||||
CompileTimeErrorCode.CONST_EVAL_ASSERTION_FAILURE,
|
||||
CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD,
|
||||
CompileTimeErrorCode.CONST_EVAL_EXTENSION_TYPE_METHOD,
|
||||
CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT,
|
||||
CompileTimeErrorCode.CONST_EVAL_METHOD_INVOCATION,
|
||||
CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS,
|
||||
|
|
|
@ -2705,6 +2705,8 @@ CompileTimeErrorCode:
|
|||
problemMessage: "The assertion in this constant expression failed."
|
||||
CONST_EVAL_EXTENSION_METHOD:
|
||||
problemMessage: "Extension methods can't be used in constant expressions."
|
||||
CONST_EVAL_EXTENSION_TYPE_METHOD:
|
||||
problemMessage: "Extension type methods can't be used in constant expressions."
|
||||
CONST_EVAL_FOR_ELEMENT:
|
||||
problemMessage: "Constant expressions don't support 'for' elements."
|
||||
correctionMessage: "Try replacing the 'for' element with a spread, or removing 'const'."
|
||||
|
|
|
@ -977,6 +977,35 @@ const v2 = v1 + v1;
|
|||
_assertNull(result);
|
||||
}
|
||||
|
||||
test_visitBinaryExpression_extensionType() async {
|
||||
await assertErrorsInCode('''
|
||||
extension type const A(int it) {
|
||||
int operator +(Object other) => 0;
|
||||
}
|
||||
|
||||
const v1 = A(1);
|
||||
const v2 = v1 + 2;
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_EVAL_EXTENSION_TYPE_METHOD, 101, 6),
|
||||
]);
|
||||
final result = _topLevelVar('v2');
|
||||
_assertNull(result);
|
||||
}
|
||||
|
||||
test_visitBinaryExpression_extensionType_implementsInt() async {
|
||||
await assertNoErrorsInCode('''
|
||||
extension type const A(int it) implements int {}
|
||||
|
||||
const v1 = A(1);
|
||||
const v2 = v1 + 2;
|
||||
''');
|
||||
final result = _topLevelVar('v2');
|
||||
assertDartObjectText(result, r'''
|
||||
int 3
|
||||
variable: self::@variable::v2
|
||||
''');
|
||||
}
|
||||
|
||||
test_visitBinaryExpression_gt_int_int() async {
|
||||
await assertNoErrorsInCode('''
|
||||
const c = 2 > 3;
|
||||
|
@ -2522,6 +2551,35 @@ const v2 = -v1;
|
|||
_assertNull(result);
|
||||
}
|
||||
|
||||
test_visitPrefixExpression_extensionType() async {
|
||||
await assertErrorsInCode('''
|
||||
extension type const A(int it) {
|
||||
int operator -() => 0;
|
||||
}
|
||||
|
||||
const v1 = A(1);
|
||||
const v2 = -v1;
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_EVAL_EXTENSION_TYPE_METHOD, 89, 3),
|
||||
]);
|
||||
final result = _topLevelVar('v2');
|
||||
_assertNull(result);
|
||||
}
|
||||
|
||||
test_visitPrefixExpression_extensionType_implementsInt() async {
|
||||
await assertNoErrorsInCode('''
|
||||
extension type const A(int it) implements int {}
|
||||
|
||||
const v1 = A(1);
|
||||
const v2 = -v1;
|
||||
''');
|
||||
final result = _topLevelVar('v2');
|
||||
assertDartObjectText(result, r'''
|
||||
int -1
|
||||
variable: self::@variable::v2
|
||||
''');
|
||||
}
|
||||
|
||||
test_visitPrefixExpression_logicalNot() async {
|
||||
await assertNoErrorsInCode('''
|
||||
const c = !true;
|
||||
|
@ -4235,6 +4293,35 @@ const b = B('');
|
|||
]);
|
||||
}
|
||||
|
||||
test_visitPropertyAccess_length_extensionType() async {
|
||||
await assertErrorsInCode('''
|
||||
extension type const A(String it) {
|
||||
int get length => 0;
|
||||
}
|
||||
|
||||
const v1 = A('');
|
||||
const v2 = v1.length;
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_EVAL_EXTENSION_TYPE_METHOD, 91, 9),
|
||||
]);
|
||||
final result = _topLevelVar('v2');
|
||||
_assertNull(result);
|
||||
}
|
||||
|
||||
test_visitPropertyAccess_length_extensionType_implementsString() async {
|
||||
await assertNoErrorsInCode('''
|
||||
extension type const A(String it) implements String {}
|
||||
|
||||
const v1 = A('abc');
|
||||
const v2 = v1.length;
|
||||
''');
|
||||
final result = _topLevelVar('v2');
|
||||
assertDartObjectText(result, r'''
|
||||
int 3
|
||||
variable: self::@variable::v2
|
||||
''');
|
||||
}
|
||||
|
||||
test_visitPropertyAccess_length_unresolvedType() async {
|
||||
await assertErrorsInCode('''
|
||||
class B {
|
||||
|
|
Loading…
Reference in a new issue