Create a common generator class to handle non-lvalues.

This allows all non-lvalue cases to be integrated with the analyzer
using a common code path.

Change-Id: I15cd2bc07a2d3609e78886609f3e29ee6aa807fc
Reviewed-on: https://dart-review.googlesource.com/66402
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This commit is contained in:
Paul Berry
2018-07-24 21:34:50 +00:00
committed by commit-bot@chromium.org
parent 1fe0518d3b
commit 55c0857037
18 changed files with 488 additions and 162 deletions
@@ -116,9 +116,11 @@ class ResolutionApplier extends GeneralizingAstVisitor {
node.rightHandSide.accept(this);
SyntacticEntity entity = _getAssignmentEntity(node.leftHandSide);
var data = _get(entity);
node.staticElement = _translateAuxiliaryReference(data.combiner);
node.staticType = _translateType(data.inferredType);
if (entity != null) {
var data = _get(entity);
node.staticElement = _translateAuxiliaryReference(data.combiner);
node.staticType = _translateType(data.inferredType);
}
}
@override
@@ -541,9 +543,11 @@ class ResolutionApplier extends GeneralizingAstVisitor {
void visitPostfixExpression(PostfixExpression node) {
node.operand.accept(this);
SyntacticEntity entity = _getAssignmentEntity(node.operand);
var data = _get(entity);
node.staticElement = _translateAuxiliaryReference(data.combiner);
node.staticType = _translateType(data.inferredType);
if (entity != null) {
var data = _get(entity);
node.staticElement = _translateAuxiliaryReference(data.combiner);
node.staticType = _translateType(data.inferredType);
}
}
@override
@@ -561,9 +565,11 @@ class ResolutionApplier extends GeneralizingAstVisitor {
// ++v;
// This is an assignment, it is associated with the operand.
SyntacticEntity entity = _getAssignmentEntity(node.operand);
var data = _get(entity);
node.staticElement = _translateAuxiliaryReference(data.combiner);
node.staticType = _translateType(data.inferredType);
if (entity != null) {
var data = _get(entity);
node.staticElement = _translateAuxiliaryReference(data.combiner);
node.staticType = _translateType(data.inferredType);
}
} else if (tokenType == TokenType.BANG) {
// !boolExpression;
node.staticType = _translateType(_get(node).inferredType);
@@ -732,8 +738,7 @@ class ResolutionApplier extends GeneralizingAstVisitor {
} else if (leftHandSide is ParenthesizedExpression) {
return leftHandSide.rightParenthesis;
} else {
throw new StateError(
'Unexpected LHS (${leftHandSide.runtimeType}) $leftHandSide');
return null;
}
}
@@ -6368,7 +6368,13 @@ class C {
''');
await computeAnalysisResult(source);
assertErrors(
source, [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
source,
useCFE
? [
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
CompileTimeErrorCode.NOT_AN_LVALUE
]
: [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
verify([source]);
}
@@ -6382,7 +6388,13 @@ f() {
''');
await computeAnalysisResult(source);
assertErrors(
source, [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
source,
useCFE
? [
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
CompileTimeErrorCode.NOT_AN_LVALUE
]
: [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
verify([source]);
}
@@ -6398,7 +6410,13 @@ class C {
''');
await computeAnalysisResult(source);
assertErrors(
source, [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
source,
useCFE
? [
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
CompileTimeErrorCode.NOT_AN_LVALUE
]
: [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
verify([source]);
}
@@ -6412,7 +6430,13 @@ f() {
''');
await computeAnalysisResult(source);
assertErrors(
source, [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
source,
useCFE
? [
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
CompileTimeErrorCode.NOT_AN_LVALUE
]
: [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
verify([source]);
}
@@ -6625,7 +6649,13 @@ f() {
''');
await computeAnalysisResult(source);
assertErrors(
source, [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
source,
useCFE
? [
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
CompileTimeErrorCode.NOT_AN_LVALUE
]
: [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
verify([source]);
}
@@ -837,6 +837,32 @@ void main() {
}
}
test_assignment_of_postfix_increment() async {
addTestFile('''
f(int x, int y) {
x++ = y;
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var xElement = findElement.parameter('x');
assertElement(findNode.simple('x++'), xElement);
var yElement = findElement.parameter('y');
assertElement(findNode.simple('y;'), yElement);
}
test_assignment_of_unresolved_name() async {
addTestFile('''
f(int y) {
x = y;
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var yElement = findElement.parameter('y');
assertElement(findNode.simple('y;'), yElement);
}
test_assignment_to_final_parameter() async {
addTestFile('''
f(final int x) {
@@ -963,6 +989,21 @@ main() {
expect(xReference.staticType.toString(), useCFE ? 'dynamic' : 'int');
}
test_assignment_to_non_generator() async {
addTestFile('''
f() {}
g(x) {
f() = x;
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var fElement = findElement.function('f');
assertElement(findNode.simple('f() ='), fElement);
var xElement = findElement.parameter('x');
assertElement(findNode.simple('x;'), xElement);
}
test_assignment_to_prefix() async {
var a = _p('/test/lib/a.dart');
provider.newFile(a, '''
@@ -2039,6 +2080,32 @@ var v = (() => 42)();
expect(closureElement.enclosingElement, same(variableInitializer));
}
test_compound_assignment_of_postfix_increment() async {
addTestFile('''
f(int x, int y) {
x++ += y;
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var xElement = findElement.parameter('x');
assertElement(findNode.simple('x++'), xElement);
var yElement = findElement.parameter('y');
assertElement(findNode.simple('y;'), yElement);
}
test_compound_assignment_of_unresolved_name() async {
addTestFile('''
f(int y) {
x += y;
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var yElement = findElement.parameter('y');
assertElement(findNode.simple('y;'), yElement);
}
test_conditionalExpression() async {
String content = r'''
void main() {
@@ -2474,6 +2541,18 @@ main() async {
}
}
test_dual_increment() async {
addTestFile('''
f(int x) {
++x++;
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var xElement = findElement.parameter('x');
assertElement(findNode.simple('x++'), xElement);
}
test_enum_toString() async {
addTestFile(r'''
enum MyEnum { A, B, C }
@@ -6303,6 +6382,43 @@ void f<T, U>(T a, U b) {}
}
}
test_null_aware_assignment_of_postfix_increment() async {
addTestFile('''
f(int x, int y) {
x++ ??= y;
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var xElement = findElement.parameter('x');
assertElement(findNode.simple('x++'), xElement);
var yElement = findElement.parameter('y');
assertElement(findNode.simple('y;'), yElement);
}
test_postfix_increment_of_non_generator() async {
addTestFile('''
f() {}
g() {
f()++;
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var fElement = findElement.function('f');
assertElement(findNode.simple('f()++;'), fElement);
}
test_postfix_increment_of_unresolved_name() async {
addTestFile('''
f() {
x++;
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
}
test_postfixExpression_local() async {
String content = r'''
main() {
@@ -6377,6 +6493,31 @@ class C {
}
}
test_prefix_increment_of_non_generator() async {
addTestFile('''
f() {}
g() {
++f();
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var fReference = findNode.simple('f();');
expect(fReference.parent, const TypeMatcher<MethodInvocation>());
var fElement = findElement.function('f');
assertElement(fReference, fElement);
}
test_prefix_increment_of_unresolved_name() async {
addTestFile('''
f() {
++x;
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
}
test_prefixedIdentifier_classInstance_instanceField() async {
String content = r'''
main() {
@@ -9431,6 +9572,24 @@ class FindElement {
fail('Not found class method: $name');
}
ParameterElement parameter(String name) {
ParameterElement parameterElement;
for (var function in unitElement.functions) {
for (var parameter in function.parameters) {
if (parameter.name == name) {
if (parameterElement != null) {
throw new StateError('Parameter name $name is not unique.');
}
parameterElement = parameter;
}
}
}
if (parameterElement != null) {
return parameterElement;
}
fail('No parameter found with name $name');
}
PrefixElement prefix(String name) {
for (var import_ in unitElement.library.imports) {
var prefix = import_.prefix;
@@ -6,6 +6,8 @@ library fasta.body_builder;
import 'dart:core' hide MapEntry;
import 'package:front_end/src/fasta/kernel/kernel_expression_generator.dart';
import '../constant_context.dart' show ConstantContext;
import '../fasta_codes.dart' as fasta;
@@ -81,6 +83,7 @@ import 'expression_generator.dart'
IndexedAccessGenerator,
LargeIntAccessGenerator,
LoadLibraryGenerator,
NonLvalueGenerator,
ParenthesizedExpressionGenerator,
PrefixUseGenerator,
ReadOnlyAccessGenerator,
@@ -1932,20 +1935,27 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
pop(); // block
}
Generator popForLvalue(Token token) {
Object value = pop();
if (value is Generator) {
return value.asLvalue();
} else {
return new NonLvalueGenerator(
this,
token,
buildCompileTimeError(fasta.messageNotAnLvalue, offsetForToken(token),
lengthForToken(token)),
toValue(value));
}
}
@override
void handleAssignmentExpression(Token token) {
debugEvent("AssignmentExpression");
Expression value = popForValue();
Object generator = pop();
if (generator is! Generator) {
push(new SyntheticExpressionJudgment(buildCompileTimeError(
fasta.messageNotAnLvalue,
offsetForToken(token),
lengthForToken(token))));
} else {
push(new DelayedAssignment(
this, token, generator, value, token.stringValue));
}
var generator = popForLvalue(token);
push(new DelayedAssignment(
this, token, generator, value, token.stringValue));
}
@override
@@ -2648,27 +2658,17 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
@override
void handleUnaryPrefixAssignmentExpression(Token token) {
debugEvent("UnaryPrefixAssignmentExpression");
Object generator = pop();
if (generator is Generator) {
push(generator.buildPrefixIncrement(incrementOperator(token),
offset: token.charOffset));
} else {
push(
wrapInCompileTimeError(toValue(generator), fasta.messageNotAnLvalue));
}
var generator = popForLvalue(token);
push(generator.buildPrefixIncrement(incrementOperator(token),
offset: token.charOffset));
}
@override
void handleUnaryPostfixAssignmentExpression(Token token) {
debugEvent("UnaryPostfixAssignmentExpression");
Object generator = pop();
if (generator is Generator) {
push(new DelayedPostfixIncrement(
this, token, generator, incrementOperator(token), null));
} else {
push(
wrapInCompileTimeError(toValue(generator), fasta.messageNotAnLvalue));
}
var generator = popForLvalue(token);
push(new DelayedPostfixIncrement(
this, token, generator, incrementOperator(token), null));
}
@override
@@ -3372,7 +3372,7 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
TypePromotionFact fact =
typePromoter.getFactForAccess(variable, functionNestingLevel);
TypePromotionScope scope = typePromoter.currentScope;
syntheticAssignment = lvalue.buildAssignment(
syntheticAssignment = lvalue.asLvalue().buildAssignment(
new VariableGetJudgment(variable, fact, scope)
..fileOffset = inKeyword.offset,
voidContext: true);
@@ -17,6 +17,7 @@ import '../fasta_codes.dart'
messageCantUsePrefixWithNullAware,
messageInvalidInitializer,
messageNotAConstantExpression,
messageNotAnLvalue,
templateCantUseDeferredPrefixAsConstant,
templateDeferredTypeAnnotation,
templateIntegerLiteralIsOutOfRange,
@@ -66,6 +67,8 @@ import 'kernel_ast_api.dart'
DartType,
DynamicType,
Expression,
ExpressionJudgment,
IllegalAssignmentJudgment,
Initializer,
InvalidConstructorInvocationJudgment,
InvalidType,
@@ -107,6 +110,96 @@ export 'kernel_expression_generator.dart'
ThisAccessGenerator,
buildIsNull;
class NonLvalueGenerator extends Generator {
final Expression errorExpression;
final ExpressionJudgment judgment;
final assignmentOffset;
NonLvalueGenerator(ExpressionGeneratorHelper helper, Token token,
this.errorExpression, this.judgment,
{this.assignmentOffset = -1})
: super(helper, token);
@override
Generator asLvalue() => this;
@override
Expression buildAssignment(Expression value, {bool voidContext}) {
return makeJudgment(value);
}
@override
Expression buildCompoundAssignment(Name binaryOperator, Expression value,
{int offset,
bool voidContext,
Procedure interfaceTarget,
bool isPreIncDec}) {
return makeJudgment(value);
}
@override
Expression buildNullAwareAssignment(
Expression value, DartType type, int offset,
{bool voidContext}) {
return makeJudgment(value);
}
@override
Expression buildPostfixIncrement(Name binaryOperator,
{int offset, bool voidContext, Procedure interfaceTarget}) {
return makeJudgment(null);
}
@override
Expression buildPrefixIncrement(Name binaryOperator,
{int offset, bool voidContext, Procedure interfaceTarget}) {
return makeJudgment(null);
}
@override
Expression buildSimpleRead() {
return makeJudgment(null);
}
@override
Expression makeInvalidRead() {
return makeJudgment(null);
}
@override
Expression makeInvalidWrite(Expression value) {
return makeJudgment(value);
}
@override
String get debugName {
return unhandled('debugName', 'NonLvalueGenerator', token.offset, uri);
}
@override
doInvocation(int offset, Arguments arguments) {
return unhandled('doInvocation', 'NonLvalueGenerator', token.offset, uri);
}
Expression makeJudgment(ExpressionJudgment rhs) {
return new IllegalAssignmentJudgment(errorExpression, judgment, rhs,
assignmentOffset: assignmentOffset);
}
@override
String get plainNameForRead {
return unhandled(
'plainNameForRead', 'NonLvalueGenerator', token.offset, uri);
}
@override
void printOn(StringSink sink) {
return unhandled('printOn', 'NonLvalueGenerator', token.offset, uri);
}
}
abstract class ExpressionGenerator {
/// Builds a [Expression] representing a read from the generator.
Expression buildSimpleRead();
@@ -189,6 +282,8 @@ abstract class Generator implements ExpressionGenerator {
bool get isInitializer => false;
Generator asLvalue();
Expression buildForEffect() => buildSimpleRead();
Initializer buildFieldInitializer(Map<String, int> initializedFields) {
@@ -233,6 +328,15 @@ abstract class Generator implements ExpressionGenerator {
return new UnexpectedQualifiedUseGenerator(helper, name, this, false);
}
Generator makeNonLValueGenerator() {
return new NonLvalueGenerator(
helper,
token,
helper.buildCompileTimeError(
messageNotAnLvalue, offsetForToken(token), lengthForToken(token)),
buildSimpleRead());
}
Expression invokeConstructor(List<DartType> typeArguments, String name,
Arguments arguments, Token nameToken, Constness constness) {
if (typeArguments != null) {
@@ -277,6 +381,9 @@ abstract class VariableUseGenerator implements Generator {
.variableUseGenerator(helper, token, variable, promotedType);
}
@override
Generator asLvalue() => this;
@override
String get debugName => "VariableUseGenerator";
}
@@ -312,6 +419,9 @@ abstract class PropertyAccessGenerator implements Generator {
}
}
@override
Generator asLvalue() => this;
@override
String get debugName => "PropertyAccessGenerator";
@@ -328,6 +438,9 @@ abstract class ThisPropertyAccessGenerator implements Generator {
.thisPropertyAccessGenerator(helper, token, name, getter, setter);
}
@override
Generator asLvalue() => this;
@override
String get debugName => "ThisPropertyAccessGenerator";
@@ -348,6 +461,9 @@ abstract class NullAwarePropertyAccessGenerator implements Generator {
helper, token, receiverExpression, name, getter, setter, type);
}
@override
Generator asLvalue() => this;
@override
String get debugName => "NullAwarePropertyAccessGenerator";
}
@@ -359,6 +475,9 @@ abstract class SuperPropertyAccessGenerator implements Generator {
.superPropertyAccessGenerator(helper, token, name, getter, setter);
}
@override
Generator asLvalue() => this;
@override
String get debugName => "SuperPropertyAccessGenerator";
}
@@ -391,6 +510,9 @@ abstract class IndexedAccessGenerator implements Generator {
}
}
@override
Generator asLvalue() => this;
@override
String get plainNameForRead => "[]";
@@ -410,6 +532,9 @@ abstract class ThisIndexedAccessGenerator implements Generator {
.thisIndexedAccessGenerator(helper, token, index, getter, setter);
}
@override
Generator asLvalue() => this;
@override
String get plainNameForRead => "[]";
@@ -427,6 +552,9 @@ abstract class SuperIndexedAccessGenerator implements Generator {
.superIndexedAccessGenerator(helper, token, index, getter, setter);
}
@override
Generator asLvalue() => this;
String get plainNameForRead => "[]";
String get plainNameForWrite => "[]=";
@@ -466,6 +594,9 @@ abstract class StaticAccessGenerator implements Generator {
return new StaticAccessGenerator(helper, token, getter, setter);
}
@override
Generator asLvalue() => this;
Member get readTarget;
@override
@@ -478,6 +609,9 @@ abstract class LoadLibraryGenerator implements Generator {
return helper.forest.loadLibraryGenerator(helper, token, builder);
}
@override
Generator asLvalue() => makeNonLValueGenerator();
@override
String get plainNameForRead => 'loadLibrary';
@@ -496,6 +630,9 @@ abstract class DeferredAccessGenerator implements Generator {
Generator get suffixGenerator;
@override
Generator asLvalue() => this;
@override
buildPropertyAccess(
IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
@@ -572,6 +709,9 @@ abstract class TypeUseGenerator implements Generator {
@override
String get debugName => "TypeUseGenerator";
@override
Generator asLvalue() => makeNonLValueGenerator();
@override
DartType buildTypeWithBuiltArguments(List<DartType> arguments,
{bool nonInstanceAccessIsError: false, TypeInferrer typeInferrer}) {
@@ -674,6 +814,9 @@ abstract class ReadOnlyAccessGenerator implements Generator {
@override
String get debugName => "ReadOnlyAccessGenerator";
@override
Generator asLvalue() => makeNonLValueGenerator();
}
abstract class LargeIntAccessGenerator implements Generator {
@@ -689,6 +832,9 @@ abstract class LargeIntAccessGenerator implements Generator {
@override
String get debugName => "LargeIntAccessGenerator";
@override
Generator asLvalue() => makeNonLValueGenerator();
Expression buildError() {
return helper.buildCompileTimeError(
templateIntegerLiteralIsOutOfRange.withArguments(token),
@@ -722,6 +868,9 @@ abstract class ErroneousExpressionGenerator implements Generator {
withReceiver(Object receiver, int operatorOffset, {bool isNullAware}) => this;
@override
Generator asLvalue() => this;
@override
Initializer buildFieldInitializer(Map<String, int> initializedFields) {
return helper.buildInvalidInitializer(new SyntheticExpressionJudgment(
@@ -842,7 +991,7 @@ abstract class UnresolvedNameGenerator implements ErroneousExpressionGenerator {
offset ??= offsetForToken(this.token);
return helper.throwNoSuchMethodError(
forest.literalNull(null)..fileOffset = offset,
plainNameForRead,
plainNameForRead ?? '',
arguments,
offset,
isGetter: isGetter,
@@ -870,6 +1019,9 @@ abstract class UnlinkedGenerator implements Generator {
@override
String get debugName => "UnlinkedGenerator";
@override
Generator asLvalue() => this;
@override
void printOn(StringSink sink) {
sink.write(", name: ");
@@ -950,6 +1102,9 @@ abstract class DelayedAssignment implements ContextAwareGenerator {
@override
String get debugName => "DelayedAssignment";
@override
Generator asLvalue() => makeNonLValueGenerator();
@override
Expression buildSimpleRead() {
return handleAssignment(false);
@@ -1035,6 +1190,9 @@ abstract class DelayedPostfixIncrement implements ContextAwareGenerator {
@override
String get debugName => "DelayedPostfixIncrement";
@override
Generator asLvalue() => makeNonLValueGenerator();
@override
Expression buildSimpleRead() {
return generator.buildPostfixIncrement(binaryOperator,
@@ -1074,6 +1232,9 @@ abstract class PrefixUseGenerator implements Generator {
@override
String get debugName => "PrefixUseGenerator";
@override
Generator asLvalue() => makeNonLValueGenerator();
@override
Expression buildSimpleRead() => makeInvalidRead();
@@ -1144,9 +1305,6 @@ abstract class PrefixUseGenerator implements Generator {
lengthForToken(token)));
}
@override
Expression makeInvalidWrite(Expression value) => makeInvalidRead();
@override
void printOn(StringSink sink) {
sink.write(", prefix: ");
@@ -1175,6 +1333,9 @@ abstract class UnexpectedQualifiedUseGenerator implements Generator {
@override
String get debugName => "UnexpectedQualifiedUseGenerator";
@override
Generator asLvalue() => makeNonLValueGenerator();
@override
Expression buildSimpleRead() => makeInvalidRead();
@@ -96,7 +96,6 @@ export 'kernel_shadow_ast.dart'
InvalidStatementJudgment,
InvalidSuperInitializerJudgment,
InvalidVariableWriteJudgment,
InvalidWriteJudgment,
ShadowInvalidFieldInitializer,
ShadowInvalidInitializer,
LabeledStatementJudgment,
@@ -47,6 +47,7 @@ import 'expression_generator.dart'
IndexedAccessGenerator,
LargeIntAccessGenerator,
LoadLibraryGenerator,
NonLvalueGenerator,
NullAwarePropertyAccessGenerator,
PrefixUseGenerator,
PropertyAccessGenerator,
@@ -77,13 +78,11 @@ import 'kernel_ast_api.dart'
Constructor,
DartType,
Field,
IllegalAssignmentJudgment,
IndexAssignmentJudgment,
Initializer,
InvalidPropertyGetJudgment,
InvalidType,
InvalidVariableWriteJudgment,
InvalidWriteJudgment,
Let,
LoadLibraryTearOffJudgment,
Member,
@@ -247,7 +246,7 @@ abstract class KernelExpressionGenerator implements ExpressionGenerator {
Expression makeInvalidWrite(Expression value) {
return buildInvalidWriteJudgment(helper.throwNoSuchMethodError(
forest.literalNull(token),
plainNameForRead,
plainNameForRead ?? '',
forest.arguments(<Expression>[value], noLocation),
offsetForToken(token),
isSetter: true));
@@ -289,8 +288,13 @@ abstract class KernelExpressionGenerator implements ExpressionGenerator {
/// Creates a data structure for tracking the desugaring of a complex
/// assignment expression whose right hand side is [rhs].
ComplexAssignmentJudgment startComplexAssignment(Expression rhs) =>
new IllegalAssignmentJudgment(rhs);
ComplexAssignmentJudgment startComplexAssignment(Expression rhs) {
// This code should never be reached; clients should always use .asLvalue()
// prior to starting a complex assignment, and generators returned by
// .asLvalue() should always override this method.
return unhandled(
'startComplexAssignment', '$runtimeType', token.offset, null);
}
}
abstract class KernelGenerator = Generator with KernelExpressionGenerator;
@@ -32,6 +32,9 @@ class ThisAccessGenerator extends KernelGenerator {
String get debugName => "ThisAccessGenerator";
@override
Generator asLvalue() => makeNonLValueGenerator();
Expression buildSimpleRead() {
if (!isSuper) {
return forest.thisExpression(token);
@@ -129,46 +132,6 @@ class ThisAccessGenerator extends KernelGenerator {
}
}
Expression buildAssignment(Expression value, {bool voidContext: false}) {
return buildAssignmentError();
}
Expression buildNullAwareAssignment(
Expression value, DartType type, int offset,
{bool voidContext: false}) {
return buildAssignmentError();
}
Expression buildCompoundAssignment(Name binaryOperator, Expression value,
{int offset: TreeNode.noOffset,
bool voidContext: false,
Procedure interfaceTarget,
bool isPreIncDec: false,
bool isPostIncDec: false}) {
return buildAssignmentError();
}
Expression buildPrefixIncrement(Name binaryOperator,
{int offset: TreeNode.noOffset,
bool voidContext: false,
Procedure interfaceTarget}) {
return buildAssignmentError();
}
Expression buildPostfixIncrement(Name binaryOperator,
{int offset: TreeNode.noOffset,
bool voidContext: false,
Procedure interfaceTarget}) {
return buildAssignmentError();
}
Expression buildAssignmentError() {
String message =
isSuper ? "Can't assign to 'super'." : "Can't assign to 'this'.";
return helper.deprecated_buildCompileTimeError(
message, offsetForToken(token));
}
@override
void printOn(StringSink sink) {
sink.write(", isInitializer: ");
@@ -189,6 +152,9 @@ abstract class IncompleteSendGenerator extends KernelGenerator {
Arguments get arguments => null;
@override
Generator asLvalue() => makeNonLValueGenerator();
@override
void printOn(StringSink sink) {
sink.write(", name: ");
@@ -378,16 +344,15 @@ class ParenthesizedExpressionGenerator extends KernelReadOnlyAccessGenerator {
String get debugName => "ParenthesizedExpressionGenerator";
@override
ComplexAssignmentJudgment startComplexAssignment(Expression rhs) {
return new IllegalAssignmentJudgment(rhs,
Generator asLvalue() {
return new NonLvalueGenerator(
helper,
token,
helper.buildCompileTimeError(
messageCannotAssignToParenthesizedExpression,
offsetForToken(token),
lengthForToken(token)),
buildSimpleRead(),
assignmentOffset: offsetForToken(token));
}
Expression makeInvalidWrite(Expression value) {
var error = helper.buildCompileTimeError(
messageCannotAssignToParenthesizedExpression,
offsetForToken(token),
lengthForToken(token));
return new InvalidWriteJudgment(error, expression);
}
}
@@ -1574,35 +1574,44 @@ class IfJudgment extends IfStatement implements StatementJudgment {
}
}
/// Concrete shadow object representing an assignment to a target for which
/// assignment is not allowed.
class IllegalAssignmentJudgment extends ComplexAssignmentJudgment {
class IllegalAssignmentJudgment extends SyntheticExpressionJudgment {
/// The offset at which the invalid assignment should be stored.
/// If `-1`, then there is no separate location for invalid assignment.
final int assignmentOffset;
IllegalAssignmentJudgment(ExpressionJudgment rhs, {this.assignmentOffset: -1})
: super(rhs) {
rhs.parent = this;
IllegalAssignmentJudgment(kernel.Expression desugared, this.lhs, this.rhs,
{this.assignmentOffset: -1})
: super(desugared) {
// lhs and rhs may not be hooked up to the expression tree because they're
// not meant to be part of the compiled output; they only exist to allow
// resolution information to be reported to the analyzer. But type
// inference currently requires expressions to have a parent (so that it can
// replace them with their desugared equivalents), so create placeholder
// parents if needed.
if (lhs.parent == null) {
new ExpressionStatement(lhs);
}
if (rhs != null && rhs.parent == null) {
new ExpressionStatement(rhs);
}
}
@override
DartType _getWriteType(ShadowTypeInferrer inferrer) {
return const UnknownType();
}
final ExpressionJudgment lhs;
final ExpressionJudgment rhs;
@override
Expression infer<Expression, Statement, Initializer, Type>(
ShadowTypeInferrer inferrer,
Factory<Expression, Statement, Initializer, Type> factory,
DartType typeContext) {
if (write != null) {
inferrer.inferExpression(factory, write, const UnknownType(), false);
}
inferrer.inferExpression(factory, lhs, const UnknownType(), false);
if (assignmentOffset != -1) {
inferrer.listener.invalidAssignment(this, assignmentOffset);
}
inferrer.inferExpression(factory, rhs, const UnknownType(), false);
if (rhs != null) {
inferrer.inferExpression(factory, rhs, const UnknownType(), false);
}
_replaceWithDesugared();
inferredType = const DynamicType();
return null;
@@ -2975,29 +2984,6 @@ class InvalidVariableWriteJudgment extends SyntheticExpressionJudgment {
}
}
/// Synthetic judgment class representing an attempt to assign to the
/// [expression] which is not assignable.
class InvalidWriteJudgment extends SyntheticExpressionJudgment {
final ExpressionJudgment expression;
InvalidWriteJudgment(kernel.Expression desugared, this.expression)
: super(desugared);
@override
Expression infer<Expression, Statement, Initializer, Type>(
ShadowTypeInferrer inferrer,
Factory<Expression, Statement, Initializer, Type> factory,
DartType typeContext) {
// When a compound assignment, the expression is already wrapping in
// VariableDeclaration in _makeRead(). Otherwise, temporary associate
// the expression with this node.
expression.parent ??= this;
inferrer.inferExpression(factory, expression, const UnknownType(), false);
return super.infer(inferrer, factory, typeContext);
}
}
/// Synthetic judgment class representing an attempt reference a member
/// that is not allowed at this location.
class InvalidPropertyGetJudgment extends SyntheticExpressionJudgment {
+1
View File
@@ -34,6 +34,7 @@ CantInferPackagesFromPackageUri/example: Fail
CantInferTypeDueToCircularity/dart2jsCode: Fail
CantInferTypeDueToCircularity/example: Fail
CantInferTypeDueToInconsistentOverrides/example: Fail
CantUsePrefixAsExpression/script: Fail
CantUseSuperBoundedTypeForInstanceCreation/analyzerCode: Fail
CantUseSuperBoundedTypeForInstanceCreation/example: Fail
ColonInPlaceOfIn/example: Fail
+1 -1
View File
@@ -96,7 +96,7 @@ rasta/type_with_parse_error: Fail
rasta/typedef: Fail
rasta/unresolved: Fail
rasta/unresolved_constructor: Fail
rasta/unresolved_for_in: RuntimeError # Test contains a compile-time error, signaled at run time in the JIT VM
rasta/unresolved_for_in: RuntimeError # Test has an intentional error
rasta/unresolved_recovery: Fail
regress/issue_29975: Fail # Issue 29975.
@@ -23,11 +23,13 @@ class Fisk extends core::Object {
core::print(this.key);
}
for (final dynamic #t2 in x) {
let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#Fisk, 34, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[#t2]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:14:10: Error: Can't assign to this.
for (Fisk in x) {
^^^^";
core::print(self::Fisk);
}
for (final dynamic #t3 in x) {
let dynamic _ = null in invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:17:10: Error: A prefix can't be used as an expression.
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:17:10: Error: Can't assign to this.
for (collection in x) {
^^^^^^^^^^";
core::print(invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:18:13: Error: A prefix can't be used as an expression.
@@ -35,7 +37,9 @@ class Fisk extends core::Object {
^^^^^^^^^^");
}
for (final dynamic #t4 in x) {
let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#VoidFunction, 34, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[#t4]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:20:10: Error: Can't assign to this.
for (VoidFunction in x) {
^^^^^^^^^^^^";
core::print(() → void);
}
for (final dynamic #t5 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:23:10: Error: Can't assign to this, so it can't be used in a for-in loop.
@@ -52,11 +56,13 @@ static method main(dynamic arguments) → dynamic {
core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#key, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
}
for (final dynamic #t7 in arguments) {
let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#Fisk, 34, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[#t7]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:34:8: Error: Can't assign to this.
for (Fisk in arguments) {
^^^^";
core::print(self::Fisk);
}
for (final dynamic #t8 in arguments) {
let dynamic _ = null in invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:37:8: Error: A prefix can't be used as an expression.
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:37:8: Error: Can't assign to this.
for (collection in arguments) {
^^^^^^^^^^";
core::print(invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:38:11: Error: A prefix can't be used as an expression.
@@ -64,7 +70,9 @@ static method main(dynamic arguments) → dynamic {
^^^^^^^^^^");
}
for (final dynamic #t9 in arguments) {
let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#VoidFunction, 34, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[#t9]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:40:8: Error: Can't assign to this.
for (VoidFunction in arguments) {
^^^^^^^^^^^^";
core::print(() → void);
}
for (final dynamic #t10 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:43:8: Error: Can't assign to this, so it can't be used in a for-in loop.
@@ -23,11 +23,13 @@ class Fisk extends core::Object {
core::print(this.key);
}
for (final dynamic #t2 in x) {
let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#Fisk, 34, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[#t2]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:14:10: Error: Can't assign to this.
for (Fisk in x) {
^^^^";
core::print(self::Fisk);
}
for (final dynamic #t3 in x) {
let dynamic _ = null in invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:17:10: Error: A prefix can't be used as an expression.
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:17:10: Error: Can't assign to this.
for (collection in x) {
^^^^^^^^^^";
core::print(invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:18:13: Error: A prefix can't be used as an expression.
@@ -35,7 +37,9 @@ class Fisk extends core::Object {
^^^^^^^^^^");
}
for (final dynamic #t4 in x) {
let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#VoidFunction, 34, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[#t4]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:20:10: Error: Can't assign to this.
for (VoidFunction in x) {
^^^^^^^^^^^^";
core::print(() → void);
}
for (final dynamic #t5 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:23:10: Error: Can't assign to this, so it can't be used in a for-in loop.
@@ -52,11 +56,13 @@ static method main(dynamic arguments) → dynamic {
core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#key, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
}
for (final dynamic #t7 in arguments) {
let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#Fisk, 34, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[#t7]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:34:8: Error: Can't assign to this.
for (Fisk in arguments) {
^^^^";
core::print(self::Fisk);
}
for (final dynamic #t8 in arguments) {
let dynamic _ = null in invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:37:8: Error: A prefix can't be used as an expression.
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:37:8: Error: Can't assign to this.
for (collection in arguments) {
^^^^^^^^^^";
core::print(invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:38:11: Error: A prefix can't be used as an expression.
@@ -64,7 +70,9 @@ static method main(dynamic arguments) → dynamic {
^^^^^^^^^^");
}
for (final dynamic #t9 in arguments) {
let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#VoidFunction, 34, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[#t9]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:40:8: Error: Can't assign to this.
for (VoidFunction in arguments) {
^^^^^^^^^^^^";
core::print(() → void);
}
for (final dynamic #t10 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:43:8: Error: Can't assign to this, so it can't be used in a for-in loop.
@@ -18,9 +18,9 @@ static method test1() → core::int {
self::i;
}
static method test2() → core::int {
return let final dynamic #t3 = self::i in let final dynamic #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
return invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
return (i) ++ (i);
^" in #t4;
^";
self::i;
}
static method main() → dynamic {
@@ -18,9 +18,9 @@ static method test1() → core::int {
self::i;
}
static method test2() → core::int {
return let final dynamic #t3 = self::i in let final dynamic #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
return invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
return (i) ++ (i);
^" in #t4;
^";
self::i;
}
static method main() → dynamic {
@@ -18,9 +18,9 @@ static method test1() → core::int {
self::i;
}
static method test2() → core::int {
return (let final dynamic #t3 = self::i in let final dynamic #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
return invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
return (i) ++ (i);
^" in #t4) as{TypeError} core::int;
^" as{TypeError} core::int;
self::i;
}
static method main() → dynamic {
@@ -18,9 +18,9 @@ static method test1() → core::int {
self::i;
}
static method test2() → core::int {
return (let final core::int #t3 = self::i in let final core::int #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
return invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
return (i) ++ (i);
^" in #t4) as{TypeError} core::int;
^" as{TypeError} core::int;
self::i;
}
static method main() → dynamic {
+1 -1
View File
@@ -6662,7 +6662,7 @@ TEST_CASE(DartAPI_ImportLibrary3) {
if (TestCase::UsingStrongMode()) {
EXPECT_ERROR(lib,
"Compilation failed file:///test-lib:4:10:"
" Error: Setter not found: 'foo'");
" Error: Can't assign to this.");
return;
}
EXPECT_VALID(lib);