Index: runtime/vm/parser.cc |
=================================================================== |
--- runtime/vm/parser.cc (revision 24832) |
+++ runtime/vm/parser.cc (working copy) |
@@ -2643,8 +2643,7 @@ |
// We have a library prefix qualified identifier, unless the prefix is |
// shadowed by a type parameter in scope. |
if (current_class().IsNull() || |
- (current_class().LookupTypeParameter(*(qual_ident->ident), |
- TokenPos()) == |
+ (current_class().LookupTypeParameter(*(qual_ident->ident)) == |
TypeParameter::null())) { |
ConsumeToken(); // Consume the kPERIOD token. |
qual_ident->lib_prefix = &lib_prefix; |
@@ -5913,12 +5912,9 @@ |
AstNode* loop_var_primary = |
ResolveIdent(loop_var_pos, *loop_var_name, false); |
ASSERT(!loop_var_primary->IsPrimaryNode()); |
- loop_var_assignment = |
- CreateAssignmentNode(loop_var_primary, iterator_current); |
- if (loop_var_assignment == NULL) { |
- ErrorMsg(loop_var_pos, "variable or field '%s' is not assignable", |
- loop_var_name->ToCString()); |
- } |
+ loop_var_assignment = CreateAssignmentNode( |
+ loop_var_primary, iterator_current, loop_var_name, loop_var_pos); |
+ ASSERT(loop_var_assignment != NULL); |
} |
current_block_->statements->Add(loop_var_assignment); |
@@ -7010,17 +7006,6 @@ |
} |
-bool Parser::IsAssignableExpr(AstNode* expr) { |
- return (expr->IsLoadLocalNode() |
- && (!expr->AsLoadLocalNode()->local().is_final())) |
- || expr->IsLoadStaticFieldNode() |
- || expr->IsStaticGetterNode() |
- || expr->IsInstanceGetterNode() |
- || expr->IsLoadIndexedNode() |
- || (expr->IsPrimaryNode() && !expr->AsPrimaryNode()->IsSuper()); |
-} |
- |
- |
AstNode* Parser::ParseExprList() { |
TRACE_PARSER("ParseExprList"); |
AstNode* expressions = ParseExpr(kAllowConst, kConsumeCascades); |
@@ -7189,25 +7174,35 @@ |
} |
-// Ensure that the expression temp is allocated for nodes that may need it. |
-AstNode* Parser::CreateAssignmentNode(AstNode* original, AstNode* rhs) { |
+AstNode* Parser::CreateAssignmentNode(AstNode* original, |
+ AstNode* rhs, |
+ const String* left_ident, |
+ intptr_t left_pos) { |
AstNode* result = original->MakeAssignmentNode(rhs); |
- if ((result == NULL) && original->IsTypeNode()) { |
- const String& type_name = String::ZoneHandle( |
- original->AsTypeNode()->type().ClassName()); |
- // TODO(tball): determine whether NoSuchMethod should be called instead. |
+ if (result == NULL) { |
+ String& name = String::ZoneHandle(); |
+ if (original->IsTypeNode()) { |
+ name = Symbols::New(original->Name()); |
+ } else if ((left_ident != NULL) && |
+ (original->IsLiteralNode() || |
+ original->IsLoadLocalNode() || |
+ original->IsLoadStaticFieldNode())) { |
+ name = left_ident->raw(); |
+ } |
+ if (name.IsNull()) { |
+ ErrorMsg(left_pos, "expression is not assignable"); |
+ } |
result = ThrowNoSuchMethodError(original->token_pos(), |
current_class(), |
- type_name, |
+ name, |
InvocationMirror::kStatic, |
InvocationMirror::kSetter); |
- } |
- if ((result != NULL) && |
- (result->IsStoreIndexedNode() || |
- result->IsInstanceSetterNode() || |
- result->IsStaticSetterNode() || |
- result->IsStoreStaticFieldNode() || |
- result->IsStoreLocalNode())) { |
+ } else if (result->IsStoreIndexedNode() || |
+ result->IsInstanceSetterNode() || |
+ result->IsStaticSetterNode() || |
+ result->IsStoreStaticFieldNode() || |
+ result->IsStoreLocalNode()) { |
+ // Ensure that the expression temp is allocated for nodes that may need it. |
EnsureExpressionTemp(); |
} |
return result; |
@@ -7230,6 +7225,9 @@ |
} else { |
ErrorMsg("identifier or [ expected after .."); |
} |
+ String* expr_ident = |
+ Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL; |
+ const intptr_t expr_pos = TokenPos(); |
expr = ParseSelectors(load_cascade_receiver, true); |
// Assignments after a cascade are part of the cascade. The |
@@ -7245,23 +7243,17 @@ |
LetNode* let_expr = PrepareCompoundAssignmentNodes(&expr); |
right_expr = |
ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr); |
- AstNode* assign_expr = CreateAssignmentNode(expr, right_expr); |
- if (assign_expr == NULL) { |
- ErrorMsg(assignment_pos, |
- "left hand side of '%s' is not assignable", |
- Token::Str(assignment_op)); |
- } |
+ AstNode* assign_expr = CreateAssignmentNode( |
+ expr, right_expr, expr_ident, expr_pos); |
+ ASSERT(assign_expr != NULL); |
let_expr->AddNode(assign_expr); |
expr = let_expr; |
} else { |
right_expr = |
ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr); |
- AstNode* assign_expr = CreateAssignmentNode(expr, right_expr); |
- if (assign_expr == NULL) { |
- ErrorMsg(assignment_pos, |
- "left hand side of '%s' is not assignable", |
- Token::Str(assignment_op)); |
- } |
+ AstNode* assign_expr = CreateAssignmentNode( |
+ expr, right_expr, expr_ident, expr_pos); |
+ ASSERT(assign_expr != NULL); |
expr = assign_expr; |
} |
} |
@@ -7277,6 +7269,8 @@ |
AstNode* Parser::ParseExpr(bool require_compiletime_const, |
bool consume_cascades) { |
TRACE_PARSER("ParseExpr"); |
+ String* expr_ident = |
+ Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL; |
const intptr_t expr_pos = TokenPos(); |
if (CurrentToken() == Token::kTHROW) { |
@@ -7296,7 +7290,7 @@ |
return expr; |
} |
// Assignment expressions. |
- Token::Kind assignment_op = CurrentToken(); |
+ const Token::Kind assignment_op = CurrentToken(); |
const intptr_t assignment_pos = TokenPos(); |
ConsumeToken(); |
const intptr_t right_expr_pos = TokenPos(); |
@@ -7309,23 +7303,17 @@ |
LetNode* let_expr = PrepareCompoundAssignmentNodes(&expr); |
AstNode* assigned_value = |
ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr); |
- AstNode* assign_expr = CreateAssignmentNode(expr, assigned_value); |
- if (assign_expr == NULL) { |
- ErrorMsg(assignment_pos, |
- "left hand side of '%s' is not assignable", |
- Token::Str(assignment_op)); |
- } |
+ AstNode* assign_expr = CreateAssignmentNode( |
+ expr, assigned_value, expr_ident, expr_pos); |
+ ASSERT(assign_expr != NULL); |
let_expr->AddNode(assign_expr); |
return let_expr; |
} else { |
AstNode* assigned_value = |
ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr); |
- AstNode* assign_expr = CreateAssignmentNode(expr, assigned_value); |
- if (assign_expr == NULL) { |
- ErrorMsg(assignment_pos, |
- "left hand side of '%s' is not assignable", |
- Token::Str(assignment_op)); |
- } |
+ AstNode* assign_expr = CreateAssignmentNode( |
+ expr, assigned_value, expr_ident, expr_pos); |
+ ASSERT(assign_expr != NULL); |
return assign_expr; |
} |
} |
@@ -7374,10 +7362,10 @@ |
} else if (IsIncrementOperator(CurrentToken())) { |
Token::Kind incr_op = CurrentToken(); |
ConsumeToken(); |
+ String* expr_ident = |
+ Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL; |
+ const intptr_t expr_pos = TokenPos(); |
expr = ParseUnaryExpr(); |
- if (!IsAssignableExpr(expr)) { |
- ErrorMsg("expression is not assignable"); |
- } |
// Is prefix. |
LetNode* let_expr = PrepareCompoundAssignmentNodes(&expr); |
Token::Kind binary_op = |
@@ -7387,7 +7375,7 @@ |
binary_op, |
expr, |
new LiteralNode(op_pos, Smi::ZoneHandle(Smi::New(1)))); |
- AstNode* store = CreateAssignmentNode(expr, add); |
+ AstNode* store = CreateAssignmentNode(expr, add, expr_ident, expr_pos); |
ASSERT(store != NULL); |
let_expr->AddNode(store); |
expr = let_expr; |
@@ -7727,6 +7715,18 @@ |
if (left->IsPrimaryNode()) { |
if (left->AsPrimaryNode()->primary().IsFunction()) { |
left = LoadClosure(left->AsPrimaryNode()); |
+ } else if (left->AsPrimaryNode()->primary().IsTypeParameter()) { |
+ if (current_block_->scope->function_level() > 0) { |
+ // Make sure that the instantiator is captured. |
+ CaptureInstantiator(); |
+ } |
+ TypeParameter& type_parameter = TypeParameter::ZoneHandle(); |
+ type_parameter ^= ClassFinalizer::FinalizeType( |
+ current_class(), |
+ TypeParameter::Cast(left->AsPrimaryNode()->primary()), |
+ ClassFinalizer::kFinalize); |
+ ASSERT(!type_parameter.IsMalformed()); |
+ left = new TypeNode(primary->token_pos(), type_parameter); |
} else { |
// Super field access handled in ParseSuperFieldAccess(), |
// super calls handled in ParseSuperCall(). |
@@ -7783,7 +7783,26 @@ |
if (primary->primary().IsFunction()) { |
array = LoadClosure(primary); |
} else if (primary->primary().IsClass()) { |
- ErrorMsg(bracket_pos, "cannot apply index operator to class"); |
+ const Class& type_class = Class::Cast(primary->primary()); |
+ Type& type = Type::ZoneHandle( |
+ Type::New(type_class, TypeArguments::Handle(), |
+ primary->token_pos(), Heap::kOld)); |
+ type ^= ClassFinalizer::FinalizeType( |
+ current_class(), type, ClassFinalizer::kCanonicalize); |
+ ASSERT(!type.IsMalformed()); |
+ array = new TypeNode(primary->token_pos(), type); |
+ } else if (primary->primary().IsTypeParameter()) { |
+ if (current_block_->scope->function_level() > 0) { |
+ // Make sure that the instantiator is captured. |
+ CaptureInstantiator(); |
+ } |
+ TypeParameter& type_parameter = TypeParameter::ZoneHandle(); |
+ type_parameter ^= ClassFinalizer::FinalizeType( |
+ current_class(), |
+ TypeParameter::Cast(primary->primary()), |
+ ClassFinalizer::kFinalize); |
+ ASSERT(!type_parameter.IsMalformed()); |
+ array = new TypeNode(primary->token_pos(), type_parameter); |
} else { |
UNREACHABLE(); // Internal parser error. |
} |
@@ -7830,9 +7849,23 @@ |
AstNode* receiver = LoadReceiver(primary->token_pos()); |
selector = ParseInstanceCall(receiver, name); |
} |
+ } else if (primary->primary().IsTypeParameter()) { |
+ const String& name = String::ZoneHandle( |
+ Symbols::New(primary->Name())); |
+ selector = ThrowNoSuchMethodError(primary->token_pos(), |
+ current_class(), |
+ name, |
+ InvocationMirror::kStatic, |
+ InvocationMirror::kMethod); |
} else if (primary->primary().IsClass()) { |
- ErrorMsg(left->token_pos(), |
- "must use 'new' or 'const' to construct new instance"); |
+ const Class& type_class = Class::Cast(primary->primary()); |
+ Type& type = Type::ZoneHandle( |
+ Type::New(type_class, TypeArguments::Handle(), |
+ primary->token_pos(), Heap::kOld)); |
+ type ^= ClassFinalizer::FinalizeType( |
+ current_class(), type, ClassFinalizer::kCanonicalize); |
+ ASSERT(!type.IsMalformed()); |
+ selector = new TypeNode(primary->token_pos(), type); |
} else { |
UNREACHABLE(); // Internal parser error. |
} |
@@ -7856,7 +7889,20 @@ |
primary->token_pos(), Heap::kOld)); |
type ^= ClassFinalizer::FinalizeType( |
current_class(), type, ClassFinalizer::kCanonicalize); |
+ ASSERT(!type.IsMalformed()); |
left = new TypeNode(primary->token_pos(), type); |
+ } else if (primary->primary().IsTypeParameter()) { |
+ if (current_block_->scope->function_level() > 0) { |
+ // Make sure that the instantiator is captured. |
+ CaptureInstantiator(); |
+ } |
+ TypeParameter& type_parameter = TypeParameter::ZoneHandle(); |
+ type_parameter ^= ClassFinalizer::FinalizeType( |
+ current_class(), |
+ TypeParameter::Cast(primary->primary()), |
+ ClassFinalizer::kFinalize); |
+ ASSERT(!type_parameter.IsMalformed()); |
+ left = new TypeNode(primary->token_pos(), type_parameter); |
} else if (primary->IsSuper()) { |
// Return "super" to handle unary super operator calls, |
// or to report illegal use of "super" otherwise. |
@@ -7876,35 +7922,34 @@ |
AstNode* Parser::ParsePostfixExpr() { |
TRACE_PARSER("ParsePostfixExpr"); |
- const intptr_t postfix_expr_pos = TokenPos(); |
- AstNode* postfix_expr = ParsePrimary(); |
- postfix_expr = ParseSelectors(postfix_expr, false); |
+ String* expr_ident = |
+ Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL; |
+ const intptr_t expr_pos = TokenPos(); |
+ AstNode* expr = ParsePrimary(); |
+ expr = ParseSelectors(expr, false); |
if (IsIncrementOperator(CurrentToken())) { |
TRACE_PARSER("IncrementOperator"); |
Token::Kind incr_op = CurrentToken(); |
- if (!IsAssignableExpr(postfix_expr)) { |
- ErrorMsg("expression is not assignable"); |
- } |
ConsumeToken(); |
// Not prefix. |
- LetNode* let_expr = PrepareCompoundAssignmentNodes(&postfix_expr); |
- LocalVariable* temp = let_expr->AddInitializer(postfix_expr); |
+ LetNode* let_expr = PrepareCompoundAssignmentNodes(&expr); |
+ LocalVariable* temp = let_expr->AddInitializer(expr); |
Token::Kind binary_op = |
(incr_op == Token::kINCR) ? Token::kADD : Token::kSUB; |
BinaryOpNode* add = new BinaryOpNode( |
- postfix_expr_pos, |
+ expr_pos, |
binary_op, |
- new LoadLocalNode(postfix_expr_pos, temp), |
- new LiteralNode(postfix_expr_pos, Smi::ZoneHandle(Smi::New(1)))); |
- AstNode* store = CreateAssignmentNode(postfix_expr, add); |
+ new LoadLocalNode(expr_pos, temp), |
+ new LiteralNode(expr_pos, Smi::ZoneHandle(Smi::New(1)))); |
+ AstNode* store = CreateAssignmentNode(expr, add, expr_ident, expr_pos); |
ASSERT(store != NULL); |
// The result is a pair of the (side effects of the) store followed by |
// the (value of the) initial value temp variable load. |
let_expr->AddNode(store); |
- let_expr->AddNode(new LoadLocalNode(postfix_expr_pos, temp)); |
+ let_expr->AddNode(new LoadLocalNode(expr_pos, temp)); |
return let_expr; |
} |
- return postfix_expr; |
+ return expr; |
} |
@@ -7934,8 +7979,7 @@ |
if (!scope_class.IsNull()) { |
// First check if the type is a type parameter of the given scope class. |
const TypeParameter& type_parameter = TypeParameter::Handle( |
- scope_class.LookupTypeParameter(unresolved_class_name, |
- type->token_pos())); |
+ scope_class.LookupTypeParameter(unresolved_class_name)); |
if (!type_parameter.IsNull()) { |
// A type parameter is considered to be a malformed type when |
// referenced by a static member. |
@@ -8640,8 +8684,7 @@ |
} |
-// Resolve identifier, issue an error message if the name refers to |
-// a class/interface or a type parameter. Issue an error message if |
+// Resolve identifier. Issue an error message if |
// the ident refers to a method and allow_closure_names is false. |
// If the name cannot be resolved, turn it into an instance field access |
// if we're compiling an instance method, or issue an error message |
@@ -8655,15 +8698,19 @@ |
AstNode* resolved = NULL; |
ResolveIdentInLocalScope(ident_pos, ident, &resolved); |
if (resolved == NULL) { |
- // Check whether the identifier is a type parameter. Type parameters |
- // can never be used in primary expressions. |
+ // Check whether the identifier is a type parameter. |
if (!current_class().IsNull()) { |
- TypeParameter& type_param = TypeParameter::Handle( |
- current_class().LookupTypeParameter(ident, ident_pos)); |
- if (!type_param.IsNull()) { |
- String& type_param_name = String::Handle(type_param.name()); |
- ErrorMsg(ident_pos, "illegal use of type parameter %s", |
- type_param_name.ToCString()); |
+ TypeParameter& type_parameter = TypeParameter::ZoneHandle( |
+ current_class().LookupTypeParameter(ident)); |
+ if (!type_parameter.IsNull()) { |
+ if (current_block_->scope->function_level() > 0) { |
+ // Make sure that the instantiator is captured. |
+ CaptureInstantiator(); |
+ } |
+ type_parameter ^= ClassFinalizer::FinalizeType( |
+ current_class(), type_parameter, ClassFinalizer::kFinalize); |
+ ASSERT(!type_parameter.IsMalformed()); |
+ return new TypeNode(ident_pos, type_parameter); |
} |
} |
// Not found in the local scope, and the name is not a type parameter. |
@@ -8696,10 +8743,15 @@ |
ErrorMsg(ident_pos, "illegal reference to method '%s'", |
ident.ToCString()); |
} |
- } else { |
- ASSERT(primary->primary().IsClass()); |
- ErrorMsg(ident_pos, "illegal reference to class or interface '%s'", |
- ident.ToCString()); |
+ } else if (primary->primary().IsClass()) { |
+ const Class& type_class = Class::Cast(primary->primary()); |
+ Type& type = Type::ZoneHandle( |
+ Type::New(type_class, TypeArguments::Handle(), |
+ primary->token_pos(), Heap::kOld)); |
+ type ^= ClassFinalizer::FinalizeType( |
+ current_class(), type, ClassFinalizer::kCanonicalize); |
+ ASSERT(!type.IsMalformed()); |
+ resolved = new TypeNode(primary->token_pos(), type); |
} |
} |
return resolved; |
@@ -9552,17 +9604,12 @@ |
if (!ResolveIdentInLocalScope(qual_ident.ident_pos, |
*qual_ident.ident, |
&primary)) { |
- // Check whether the identifier is a type parameter. Type parameters |
- // can never be used as part of primary expressions. |
+ // Check whether the identifier is a type parameter. |
if (!current_class().IsNull()) { |
TypeParameter& type_param = TypeParameter::ZoneHandle( |
- current_class().LookupTypeParameter(*(qual_ident.ident), |
- TokenPos())); |
+ current_class().LookupTypeParameter(*(qual_ident.ident))); |
if (!type_param.IsNull()) { |
- const String& type_param_name = String::Handle(type_param.name()); |
- ErrorMsg(qual_ident.ident_pos, |
- "illegal use of type parameter %s", |
- type_param_name.ToCString()); |
+ return new PrimaryNode(qual_ident.ident_pos, type_param); |
} |
} |
// This is a non-local unqualified identifier so resolve the |