Initializer expressions must not access 'this'

Catch explicit and implicit accesses to 'this' in initializer list of constructors.
Review URL: https://chromereviews.googleplex.com/3517020

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@81 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
hausner@google.com 2011-10-05 22:39:25 +00:00
parent 9a664c355d
commit b8a55bf3d7
5 changed files with 34 additions and 21 deletions

View file

@ -108,11 +108,7 @@ LangGuideTest/02_Language_Constructs/02_3_Interface_Injection/A01/t04: Skip
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Const_Expressions/A04/t01: Fail # Bug 5371433
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A03/t02: Fail # Bug 5371433
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A06/t03: Fail # Bug 5371433
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A06/t04: Fail # Bug 5371433
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A08/t02: Fail # Bug 5371433
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A10/t01: Fail # Bug 5371433
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A13/t01: Fail # Bug 5371433
LangGuideTest/02_Language_Constructs/02_5_Meaning_of_Names/Examples/A02/t01: Fail # Bug 5371433
LangGuideTest/02_Language_Constructs/02_5_Meaning_of_Names/Shadowing_and_Hiding_Names/A01/t02: Fail # Bug 5371433
LangGuideTest/02_Language_Constructs/02_5_Meaning_of_Names/Shadowing_and_Hiding_Names/A02/t01: Fail # Bug 5371433
@ -120,6 +116,12 @@ LangGuideTest/02_Language_Constructs/02_8_Static_Methods/A02/t02: Fail # Bug 537
LibTest/core/Array/length/Array/length/A01/t02: Fail # Bug 5371433
LibTest/core/Date/Date/Date/A01/t03: Fail # Bug 5371433
# The illegal constructor initializer in this test does not get compiled.
# This test does fail as it's supposed to when invoked with the --compile_all flag.
LangGuideTest/02_Language_Constructs/02_1_Class/02_1_Class_Construction/A08/t02: Skip
# Following tests define a main with an argument, per new specification
# we do not pass any argument to main.
LangGuideTest/07_Overriding/A05/t01: Fail,Okay

View file

@ -1024,7 +1024,7 @@ AstNode* Parser::ParseSuperCall(const String& function_name) {
String::Handle(current_class().Name()).ToCString());
}
// 'this' parameter is the first argument to super call.
AstNode* implicit_argument = LoadReceiver();
AstNode* implicit_argument = LoadReceiver(supercall_pos);
ArgumentListNode* arguments =
ParseActualParameters(implicit_argument, kAllowConst);
// Resolve the function.
@ -1068,7 +1068,7 @@ AstNode* Parser::ParseSuperFieldAccess(const String& field_name) {
ErrorMsg("class '%s' does not have a superclass",
String::Handle(current_class().Name()).ToCString());
}
AstNode* implicit_argument = LoadReceiver();
AstNode* implicit_argument = LoadReceiver(field_pos);
const String& getter_name =
String::ZoneHandle(Field::GetterName(field_name));
@ -1144,8 +1144,11 @@ AstNode* Parser::ParseSuperInitializer(const Class& cls,
}
// 'this' parameter is the first argument to super class constructor.
AstNode* implicit_argument = new LoadLocalNode(supercall_pos, *receiver);
// 'this' parameter must not be accessible to the other super call arguments.
receiver->set_invisible(true);
ArgumentListNode* arguments =
ParseActualParameters(implicit_argument, kAllowConst);
receiver->set_invisible(false);
// Resolve the constructor.
const Function& super_ctor = Function::ZoneHandle(
super_class.LookupConstructor(ctor_name));
@ -1171,10 +1174,11 @@ AstNode* Parser::ParseInitializer(const Class& cls, LocalVariable* receiver) {
const String& field_name = *ExpectIdentifier("field name expected");
ExpectToken(Token::kASSIGN);
// TODO(5412278): Need to check or ensure that the initializer expression
// does not have access to the instance fields of the object.
const bool saved_mode = SetAllowFunctionLiterals(false);
// "this" must not be accessible in initializer expressions.
receiver->set_invisible(true);
AstNode* init_expr = ParseConditionalExpr();
receiver->set_invisible(false);
SetAllowFunctionLiterals(saved_mode);
Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name));
if (field.IsNull()) {
@ -3114,7 +3118,7 @@ void Parser::CaptureReceiver() {
}
AstNode* Parser::LoadReceiver() {
AstNode* Parser::LoadReceiver(intptr_t token_pos) {
// A nested function may access 'this', referring to the receiver of the
// outermost enclosing function.
// We should not be loading the receiver from a static scope.
@ -3123,7 +3127,7 @@ AstNode* Parser::LoadReceiver() {
const bool kTestOnly = false;
LocalVariable* receiver = LookupReceiver(current_block_->scope, kTestOnly);
if (receiver == NULL) {
ErrorMsg("illegal access to 'this'");
ErrorMsg(token_pos, "illegal access to 'this'");
}
return new LoadLocalNode(token_index_, *receiver);
}
@ -5355,7 +5359,7 @@ AstNode* Parser::ParsePostfixExpr() {
name.ToCString());
} else {
// Treat as call to unresolved (instance) method.
AstNode* receiver = LoadReceiver();
AstNode* receiver = LoadReceiver(primary->token_index());
selector = ParseInstanceCall(receiver, name);
}
} else {
@ -5383,7 +5387,7 @@ AstNode* Parser::ParsePostfixExpr() {
"from static function",
func_name.ToCString());
}
selector = ParseInstanceCall(LoadReceiver(), func_name);
selector = ParseInstanceCall(LoadReceiver(primary_pos), func_name);
}
} else if (primary->primary().IsString()) {
// Primary is an unresolved name.
@ -5394,7 +5398,7 @@ AstNode* Parser::ParsePostfixExpr() {
name.ToCString());
} else {
// Treat as call to unresolved (instance) method.
AstNode* receiver = LoadReceiver();
AstNode* receiver = LoadReceiver(primary->token_index());
selector = ParseInstanceCall(receiver, name);
}
} else if (primary->primary().IsClass()) {
@ -5428,7 +5432,7 @@ AstNode* Parser::ParsePostfixExpr() {
ident.ToCString());
} else {
// Treat as call to unresolved (instance) field.
AstNode* receiver = LoadReceiver();
AstNode* receiver = LoadReceiver(primary->token_index());
postfix_expr = ParseInstanceFieldAccess(receiver, ident);
}
} else if (left->AsPrimaryNode()->primary().IsFunction()) {
@ -5450,7 +5454,7 @@ AstNode* Parser::ParsePostfixExpr() {
"illegal use of method '%s'",
funcname.ToCString());
}
AstNode* receiver = LoadReceiver();
AstNode* receiver = LoadReceiver(primary->token_index());
postfix_expr = ParseInstanceFieldAccess(receiver, funcname);
}
}
@ -5709,7 +5713,7 @@ bool Parser::ResolveIdentInLocalScope(intptr_t ident_pos,
if (!field.IsNull()) {
if (node != NULL) {
CheckInstanceFieldAccess(ident_pos, ident);
*node = CallGetter(ident_pos, LoadReceiver(), ident);
*node = CallGetter(ident_pos, LoadReceiver(ident_pos), ident);
}
return true;
}
@ -5729,7 +5733,7 @@ bool Parser::ResolveIdentInLocalScope(intptr_t ident_pos,
if (node != NULL) {
CheckInstanceFieldAccess(ident_pos, ident);
ASSERT(Type::Handle(func.result_type()).IsResolved());
*node = CallGetter(ident_pos, LoadReceiver(), ident);
*node = CallGetter(ident_pos, LoadReceiver(ident_pos), ident);
}
return true;
}
@ -5753,7 +5757,7 @@ bool Parser::ResolveIdentInLocalScope(intptr_t ident_pos,
// when we try to invoke the getter.
CheckInstanceFieldAccess(ident_pos, ident);
ASSERT(Type::Handle(func.result_type()).IsResolved());
*node = CallGetter(ident_pos, LoadReceiver(), ident);
*node = CallGetter(ident_pos, LoadReceiver(ident_pos), ident);
}
return true;
}
@ -5900,7 +5904,7 @@ AstNode* Parser::ResolveVarOrField(intptr_t ident_pos, const String& ident) {
ident.ToCString());
} else {
// Treat as call to unresolved instance field.
var_or_field = CallGetter(ident_pos, LoadReceiver(), ident);
var_or_field = CallGetter(ident_pos, LoadReceiver(ident_pos), ident);
}
} else if (primary->primary().IsFunction()) {
ErrorMsg(ident_pos, "illegal reference to method '%s'",

View file

@ -258,7 +258,7 @@ class Parser : ValueObject {
LocalVariable* LookupReceiver(LocalScope* from_scope, bool test_only);
void CaptureReceiver();
AstNode* LoadReceiver();
AstNode* LoadReceiver(intptr_t token_index);
AstNode* CallGetter(intptr_t token_index,
AstNode* object,
const String& name);

View file

@ -186,7 +186,7 @@ SourceLabel* LocalScope::LocalLookupLabel(const String& name) const {
LocalVariable* LocalScope::LocalLookupVariable(const String& name) const {
for (intptr_t i = 0; i < variables_.length(); i++) {
LocalVariable* var = variables_[i];
if (var->name().Equals(name)) {
if (var->name().Equals(name) && !var->is_invisible_) {
return var;
}
}

View file

@ -25,6 +25,7 @@ class LocalVariable : public ZoneAllocated {
type_(type),
is_final_(false),
is_captured_(false),
is_invisible_(false),
index_(LocalVariable::kUnitializedIndex_) {
ASSERT(type.IsZoneHandle());
ASSERT(type.IsFinalized());
@ -59,6 +60,10 @@ class LocalVariable : public ZoneAllocated {
index_ = index;
}
void set_invisible(bool value) {
is_invisible_ = value;
}
private:
static const int kUnitializedIndex_ = INT_MIN;
@ -71,9 +76,11 @@ class LocalVariable : public ZoneAllocated {
bool is_final_; // If true, this variable is readonly.
bool is_captured_; // If true, this variable lives in the context, otherwise
// in the stack frame.
bool is_invisible_;
int index_; // Allocation index in words relative to frame pointer (if not
// captured), or relative to the context pointer (if captured).
friend class LocalScope;
DISALLOW_COPY_AND_ASSIGN(LocalVariable);
};