mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:17:55 +00:00
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:
parent
9a664c355d
commit
b8a55bf3d7
|
@ -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
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue