mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 11:31:57 +00:00
Properly resolve top-level setters
Fixes issue 4386. When converting a getter to a setter (converting a right-hand side expression to a left-hand side, assignable entity), we need to know where to look for the setter function. Top-level setters need to be resolved in the library or prefix scope in which the getter was found. R=regis@google.com Review URL: https://codereview.chromium.org//1090373006 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@45316 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
667173800b
commit
21ca62f8bc
|
@ -561,34 +561,116 @@ AstNode* LoadIndexedNode::MakeAssignmentNode(AstNode* rhs) {
|
|||
AstNode* StaticGetterNode::MakeAssignmentNode(AstNode* rhs) {
|
||||
if (is_super_getter()) {
|
||||
ASSERT(receiver() != NULL);
|
||||
// If the static setter is not found in the superclass, noSuchMethod will be
|
||||
// called at runtime.
|
||||
const String& setter_name =
|
||||
String::ZoneHandle(Field::SetterSymbol(field_name_));
|
||||
Function& setter = Function::ZoneHandle(
|
||||
Resolver::ResolveDynamicAnyArgs(cls(), setter_name));
|
||||
if (setter.IsNull() || setter.is_abstract()) {
|
||||
// No instance setter found in super class chain,
|
||||
// noSuchMethod will be called at runtime.
|
||||
return new StaticSetterNode(token_pos(),
|
||||
receiver(),
|
||||
cls(),
|
||||
field_name_,
|
||||
rhs);
|
||||
}
|
||||
return new StaticSetterNode(token_pos(),
|
||||
receiver(),
|
||||
cls(),
|
||||
field_name(),
|
||||
field_name_,
|
||||
setter,
|
||||
rhs);
|
||||
}
|
||||
|
||||
if (owner().IsLibraryPrefix()) {
|
||||
const LibraryPrefix& prefix = LibraryPrefix::Cast(owner_);
|
||||
// The parser has already dealt with the pathological case where a
|
||||
// library imports itself. See Parser::ResolveIdentInPrefixScope()
|
||||
ASSERT(field_name_.CharAt(0) != Library::kPrivateIdentifierStart);
|
||||
|
||||
// If the prefix is not yet loaded, the getter doesn't exist. Return a
|
||||
// setter that will throw a NSME at runtime.
|
||||
if (!prefix.is_loaded()) {
|
||||
return new StaticSetterNode(token_pos(), NULL, cls(), field_name_, rhs);
|
||||
}
|
||||
|
||||
Object& obj = Object::Handle(prefix.LookupObject(field_name_));
|
||||
if (obj.IsField()) {
|
||||
const Field& field = Field::ZoneHandle(Field::Cast(obj).raw());
|
||||
if (!field.is_final()) {
|
||||
if (Isolate::Current()->TypeChecksEnabled()) {
|
||||
rhs = new AssignableNode(field.token_pos(),
|
||||
rhs,
|
||||
AbstractType::ZoneHandle(field.type()),
|
||||
field_name_);
|
||||
}
|
||||
return new StoreStaticFieldNode(token_pos(), field, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
// No field found in prefix. Look for a setter function.
|
||||
const String& setter_name = String::Handle(Field::SetterName(field_name_));
|
||||
obj = prefix.LookupObject(setter_name);
|
||||
if (obj.IsFunction()) {
|
||||
const Function& setter = Function::ZoneHandle(Function::Cast(obj).raw());
|
||||
ASSERT(setter.is_static() && setter.IsSetterFunction());
|
||||
return new StaticSetterNode(
|
||||
token_pos(), NULL, field_name_, setter, rhs);
|
||||
}
|
||||
|
||||
// No writeable field and no setter found in the prefix. Return a
|
||||
// non-existing setter that will throw an NSM error.
|
||||
return new StaticSetterNode(token_pos(), NULL, cls(), field_name_, rhs);
|
||||
}
|
||||
|
||||
if (owner().IsLibrary()) {
|
||||
const Library& library = Library::Cast(owner());
|
||||
Object& obj = Object::Handle(library.ResolveName(field_name_));
|
||||
if (obj.IsField()) {
|
||||
const Field& field = Field::ZoneHandle(Field::Cast(obj).raw());
|
||||
if (!field.is_final()) {
|
||||
if (Isolate::Current()->TypeChecksEnabled()) {
|
||||
rhs = new AssignableNode(field.token_pos(),
|
||||
rhs,
|
||||
AbstractType::ZoneHandle(field.type()),
|
||||
field_name_);
|
||||
}
|
||||
return new StoreStaticFieldNode(token_pos(), field, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
// No field found in library. Look for a setter function.
|
||||
const String& setter_name = String::Handle(Field::SetterName(field_name_));
|
||||
obj = library.ResolveName(setter_name);
|
||||
if (obj.IsFunction()) {
|
||||
const Function& setter = Function::ZoneHandle(Function::Cast(obj).raw());
|
||||
ASSERT(setter.is_static() && setter.IsSetterFunction());
|
||||
return new StaticSetterNode(token_pos(), NULL, field_name_, setter, rhs);
|
||||
}
|
||||
|
||||
// No writeable field and no setter found in the library. Return a
|
||||
// non-existing setter that will throw an NSM error.
|
||||
return new StaticSetterNode(token_pos(), NULL, cls(), field_name_, rhs);
|
||||
}
|
||||
|
||||
const Function& setter =
|
||||
Function::Handle(cls().LookupSetterFunction(field_name()));
|
||||
Function::ZoneHandle(cls().LookupSetterFunction(field_name_));
|
||||
if (!setter.IsNull() && setter.IsStaticFunction()) {
|
||||
return new StaticSetterNode(token_pos(), NULL, cls(), field_name(), rhs);
|
||||
return new StaticSetterNode(token_pos(), NULL, field_name_, setter, rhs);
|
||||
}
|
||||
// Could not find a static setter. Look for a field.
|
||||
// Access to a lazily initialized static field that has not yet been
|
||||
// initialized is compiled to a static implicit getter.
|
||||
// A setter may not exist for such a field.
|
||||
const Field& field = Field::ZoneHandle(cls().LookupStaticField(field_name()));
|
||||
const Field& field = Field::ZoneHandle(cls().LookupStaticField(field_name_));
|
||||
if (!field.IsNull()) {
|
||||
if (field.is_final()) {
|
||||
// Attempting to assign to a final variable will cause a NoSuchMethodError
|
||||
// to be thrown. Change static getter to non-existent static setter in
|
||||
// order to trigger the throw at runtime.
|
||||
return new StaticSetterNode(token_pos(), NULL, cls(), field_name(), rhs);
|
||||
return new StaticSetterNode(token_pos(), NULL, cls(), field_name_, rhs);
|
||||
}
|
||||
#if defined(DEBUG)
|
||||
const String& getter_name = String::Handle(Field::GetterName(field_name()));
|
||||
const String& getter_name = String::Handle(Field::GetterName(field_name_));
|
||||
const Function& getter =
|
||||
Function::Handle(cls().LookupStaticFunction(getter_name));
|
||||
ASSERT(!getter.IsNull() &&
|
||||
|
@ -605,7 +687,7 @@ AstNode* StaticGetterNode::MakeAssignmentNode(AstNode* rhs) {
|
|||
}
|
||||
// Didn't find a static setter or a static field. Make a call to
|
||||
// the non-existent setter to trigger a NoSuchMethodError at runtime.
|
||||
return new StaticSetterNode(token_pos(), NULL, cls(), field_name(), rhs);
|
||||
return new StaticSetterNode(token_pos(), NULL, cls(), field_name_, rhs);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1286,6 +1286,7 @@ class LoadStaticFieldNode : public AstNode {
|
|||
|
||||
const Field& field() const { return field_; }
|
||||
void set_is_deferred(bool value) { is_deferred_reference_ = value; }
|
||||
bool is_deferred_reference() const { return is_deferred_reference_; }
|
||||
|
||||
virtual void VisitChildren(AstNodeVisitor* visitor) const { }
|
||||
|
||||
|
@ -1550,6 +1551,7 @@ class StaticGetterNode : public AstNode {
|
|||
const String& field_name)
|
||||
: AstNode(token_pos),
|
||||
receiver_(receiver),
|
||||
owner_(Object::ZoneHandle(cls.raw())),
|
||||
cls_(cls),
|
||||
field_name_(field_name),
|
||||
is_deferred_reference_(false) {
|
||||
|
@ -1561,6 +1563,17 @@ class StaticGetterNode : public AstNode {
|
|||
// The receiver is required for a super getter (an instance method that
|
||||
// is resolved at compile time rather than at runtime).
|
||||
AstNode* receiver() const { return receiver_; }
|
||||
|
||||
// The getter node needs to remmeber how the getter was referenced
|
||||
// so that it can resolve a corresponding setter if necessary.
|
||||
// The owner of this getter is either a class, the top-level library scope,
|
||||
// or a prefix (if the getter has been referenced throug a library prefix).
|
||||
void set_owner(const Object& value) {
|
||||
ASSERT(value.IsLibraryPrefix() || value.IsLibrary() || value.IsClass());
|
||||
owner_ = value.raw();
|
||||
}
|
||||
const Object& owner() const { return owner_; }
|
||||
|
||||
const Class& cls() const { return cls_; }
|
||||
const String& field_name() const { return field_name_; }
|
||||
bool is_super_getter() const { return receiver_ != NULL; }
|
||||
|
@ -1577,6 +1590,7 @@ class StaticGetterNode : public AstNode {
|
|||
|
||||
private:
|
||||
AstNode* receiver_;
|
||||
Object& owner_;
|
||||
const Class& cls_;
|
||||
const String& field_name_;
|
||||
bool is_deferred_reference_;
|
||||
|
@ -1587,16 +1601,36 @@ class StaticGetterNode : public AstNode {
|
|||
|
||||
class StaticSetterNode : public AstNode {
|
||||
public:
|
||||
// Static setter with resolved setter function.
|
||||
StaticSetterNode(intptr_t token_pos,
|
||||
AstNode* receiver,
|
||||
const String& field_name,
|
||||
const Function& function,
|
||||
AstNode* value)
|
||||
: AstNode(token_pos),
|
||||
receiver_(receiver),
|
||||
cls_(Class::ZoneHandle(function.Owner())),
|
||||
field_name_(field_name),
|
||||
function_(function),
|
||||
value_(value) {
|
||||
ASSERT(function_.IsZoneHandle());
|
||||
ASSERT(function.is_static() || receiver != NULL);
|
||||
ASSERT(field_name_.IsZoneHandle());
|
||||
ASSERT(value_ != NULL);
|
||||
}
|
||||
|
||||
// For unresolved setters.
|
||||
StaticSetterNode(intptr_t token_pos,
|
||||
AstNode* receiver,
|
||||
const Class& cls,
|
||||
const String& field_name,
|
||||
AstNode* value)
|
||||
: AstNode(token_pos),
|
||||
receiver_(receiver),
|
||||
cls_(cls),
|
||||
field_name_(field_name),
|
||||
value_(value) {
|
||||
: AstNode(token_pos),
|
||||
receiver_(receiver),
|
||||
cls_(cls),
|
||||
field_name_(field_name),
|
||||
function_(Function::ZoneHandle()),
|
||||
value_(value) {
|
||||
ASSERT(cls_.IsZoneHandle());
|
||||
ASSERT(field_name_.IsZoneHandle());
|
||||
ASSERT(value_ != NULL);
|
||||
|
@ -1607,6 +1641,8 @@ class StaticSetterNode : public AstNode {
|
|||
AstNode* receiver() const { return receiver_; }
|
||||
const Class& cls() const { return cls_; }
|
||||
const String& field_name() const { return field_name_; }
|
||||
// function() returns null for unresolved setters.
|
||||
const Function& function() const { return function_; }
|
||||
AstNode* value() const { return value_; }
|
||||
|
||||
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
||||
|
@ -1619,6 +1655,7 @@ class StaticSetterNode : public AstNode {
|
|||
AstNode* receiver_;
|
||||
const Class& cls_;
|
||||
const String& field_name_;
|
||||
const Function& function_;
|
||||
AstNode* value_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(StaticSetterNode);
|
||||
|
|
|
@ -499,6 +499,7 @@ void AwaitTransformer::VisitStaticGetterNode(StaticGetterNode* node) {
|
|||
new_receiver,
|
||||
node->cls(),
|
||||
node->field_name());
|
||||
new_getter->set_owner(node->owner());
|
||||
LocalVariable* result = AddToPreambleNewTempVar(new_getter);
|
||||
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
||||
}
|
||||
|
@ -510,12 +511,20 @@ void AwaitTransformer::VisitStaticSetterNode(StaticSetterNode* node) {
|
|||
new_receiver = Transform(new_receiver);
|
||||
}
|
||||
AstNode* new_value = Transform(node->value());
|
||||
LocalVariable* result = AddToPreambleNewTempVar(
|
||||
new(Z) StaticSetterNode(node->token_pos(),
|
||||
new_receiver,
|
||||
node->cls(),
|
||||
node->field_name(),
|
||||
new_value));
|
||||
StaticSetterNode* new_setter =
|
||||
node->function().IsNull()
|
||||
? new(Z) StaticSetterNode(node->token_pos(),
|
||||
new_receiver,
|
||||
node->cls(),
|
||||
node->field_name(),
|
||||
new_value)
|
||||
: new(Z) StaticSetterNode(node->token_pos(),
|
||||
new_receiver,
|
||||
node->field_name(),
|
||||
node->function(),
|
||||
new_value);
|
||||
|
||||
LocalVariable* result = AddToPreambleNewTempVar(new_setter);
|
||||
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
||||
}
|
||||
|
||||
|
|
|
@ -3166,10 +3166,7 @@ void EffectGraphVisitor::BuildStaticSetter(StaticSetterNode* node,
|
|||
// resolved at compile time (in the caller instance getter's super class).
|
||||
// Unlike a static getter, a super getter has a receiver parameter.
|
||||
const bool is_super_setter = (node->receiver() != NULL);
|
||||
Function& setter_function =
|
||||
Function::ZoneHandle(Z, is_super_setter
|
||||
? Resolver::ResolveDynamicAnyArgs(node->cls(), setter_name)
|
||||
: node->cls().LookupStaticFunction(setter_name));
|
||||
const Function& setter_function = node->function();
|
||||
StaticCallInstr* call;
|
||||
if (setter_function.IsNull()) {
|
||||
if (is_super_setter) {
|
||||
|
|
|
@ -9343,6 +9343,7 @@ RawObject* Library::LookupImportedObject(const String& name) const {
|
|||
String& import_lib_url = String::Handle();
|
||||
String& first_import_lib_url = String::Handle();
|
||||
Object& found_obj = Object::Handle();
|
||||
String& found_obj_name = String::Handle();
|
||||
for (intptr_t i = 0; i < num_imports(); i++) {
|
||||
import ^= ImportAt(i);
|
||||
obj = import.Lookup(name);
|
||||
|
@ -9358,13 +9359,28 @@ RawObject* Library::LookupImportedObject(const String& name) const {
|
|||
// from the Dart library.
|
||||
first_import_lib_url = import_lib.url();
|
||||
found_obj = obj.raw();
|
||||
found_obj_name = obj.DictionaryName();
|
||||
} else if (import_lib_url.StartsWith(Symbols::DartScheme())) {
|
||||
// The newly found object is exported from a Dart system
|
||||
// library. It is hidden by the previously found object.
|
||||
// We continue to search.
|
||||
} else {
|
||||
// We found two different objects with the same name.
|
||||
return Object::null();
|
||||
// Note that we need to compare the names again because
|
||||
// looking up an unmangled name can return a getter or a
|
||||
// setter. A getter name is the same as the unmangled name,
|
||||
// but a setter name is different from an unmangled name or a
|
||||
// getter name.
|
||||
if (Field::IsGetterName(found_obj_name)) {
|
||||
found_obj_name = Field::NameFromGetter(found_obj_name);
|
||||
}
|
||||
String& second_obj_name = String::Handle(obj.DictionaryName());
|
||||
if (Field::IsGetterName(second_obj_name)) {
|
||||
second_obj_name = Field::NameFromGetter(second_obj_name);
|
||||
}
|
||||
if (found_obj_name.Equals(second_obj_name)) {
|
||||
return Object::null();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10337,7 +10353,7 @@ RawObject* Namespace::Lookup(const String& name) const {
|
|||
if (Field::IsGetterName(name)) {
|
||||
filter_name = &String::Handle(Field::NameFromGetter(name));
|
||||
} else if (Field::IsSetterName(name)) {
|
||||
filter_name = &String::Handle(Field::NameFromGetter(name));
|
||||
filter_name = &String::Handle(Field::NameFromSetter(name));
|
||||
} else {
|
||||
if (obj.IsNull() || obj.IsLibraryPrefix()) {
|
||||
obj = lib.LookupEntry(String::Handle(Field::GetterName(name)), &ignore);
|
||||
|
|
|
@ -3912,8 +3912,8 @@ void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) {
|
|||
if (field->has_static && has_initializer) {
|
||||
class_field.set_value(init_value);
|
||||
if (!has_simple_literal) {
|
||||
String& getter_name = String::Handle(Z,
|
||||
Field::GetterSymbol(*field->name));
|
||||
String& getter_name =
|
||||
String::Handle(Z, Field::GetterSymbol(*field->name));
|
||||
getter = Function::New(getter_name,
|
||||
RawFunction::kImplicitStaticFinalGetter,
|
||||
field->has_static,
|
||||
|
@ -3934,8 +3934,8 @@ void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) {
|
|||
|
||||
// For instance fields, we create implicit getter and setter methods.
|
||||
if (!field->has_static) {
|
||||
String& getter_name = String::Handle(Z,
|
||||
Field::GetterSymbol(*field->name));
|
||||
String& getter_name =
|
||||
String::Handle(Z, Field::GetterSymbol(*field->name));
|
||||
getter = Function::New(getter_name, RawFunction::kImplicitGetter,
|
||||
field->has_static,
|
||||
field->has_final,
|
||||
|
@ -3953,8 +3953,8 @@ void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) {
|
|||
members->AddFunction(getter);
|
||||
if (!field->has_final) {
|
||||
// Build a setter accessor for non-const fields.
|
||||
String& setter_name = String::Handle(Z,
|
||||
Field::SetterSymbol(*field->name));
|
||||
String& setter_name =
|
||||
String::Handle(Z, Field::SetterSymbol(*field->name));
|
||||
setter = Function::New(setter_name, RawFunction::kImplicitSetter,
|
||||
field->has_static,
|
||||
field->has_final,
|
||||
|
@ -10529,7 +10529,8 @@ AstNode* Parser::ParseCascades(AstNode* expr) {
|
|||
static AstNode* LiteralIfStaticConst(Zone* zone, AstNode* expr) {
|
||||
if (expr->IsLoadStaticFieldNode()) {
|
||||
const Field& field = expr->AsLoadStaticFieldNode()->field();
|
||||
if (field.is_const()) {
|
||||
if (field.is_const() &&
|
||||
!expr->AsLoadStaticFieldNode()->is_deferred_reference()) {
|
||||
ASSERT(field.value() != Object::sentinel().raw());
|
||||
ASSERT(field.value() != Object::transition_sentinel().raw());
|
||||
return new(zone) LiteralNode(expr->token_pos(),
|
||||
|
@ -10898,24 +10899,17 @@ AstNode* Parser::GenerateStaticFieldLookup(const Field& field,
|
|||
}
|
||||
|
||||
|
||||
AstNode* Parser::ParseStaticFieldAccess(const Class& cls,
|
||||
const String& field_name,
|
||||
intptr_t ident_pos,
|
||||
bool consume_cascades) {
|
||||
TRACE_PARSER("ParseStaticFieldAccess");
|
||||
// Reference to 'field_name' with explicit class as primary.
|
||||
AstNode* Parser::GenerateStaticFieldAccess(const Class& cls,
|
||||
const String& field_name,
|
||||
intptr_t ident_pos) {
|
||||
AstNode* access = NULL;
|
||||
const Field& field = Field::ZoneHandle(Z, cls.LookupStaticField(field_name));
|
||||
Function& func = Function::ZoneHandle(Z);
|
||||
if (field.IsNull()) {
|
||||
// No field, check if we have an explicit getter function.
|
||||
const String& getter_name =
|
||||
String::ZoneHandle(Z, Field::GetterName(field_name));
|
||||
const int kNumArguments = 0; // no arguments.
|
||||
func = Resolver::ResolveStatic(cls,
|
||||
getter_name,
|
||||
kNumArguments,
|
||||
Object::empty_array());
|
||||
if (func.IsNull()) {
|
||||
func = cls.LookupGetterFunction(field_name);
|
||||
if (func.IsNull() || func.IsDynamicFunction()) {
|
||||
// We might be referring to an implicit closure, check to see if
|
||||
// there is a function of the same name.
|
||||
func = cls.LookupStaticFunction(field_name);
|
||||
|
@ -11056,12 +11050,14 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) {
|
|||
} else {
|
||||
// Field access.
|
||||
Class& cls = Class::Handle(Z);
|
||||
bool is_deferred = false;
|
||||
if (left->IsPrimaryNode()) {
|
||||
PrimaryNode* primary_node = left->AsPrimaryNode();
|
||||
if (primary_node->primary().IsClass()) {
|
||||
// If the primary node referred to a class we are loading a
|
||||
// qualified static field.
|
||||
cls ^= primary_node->primary().raw();
|
||||
is_deferred = primary_node->is_deferred_reference();
|
||||
}
|
||||
}
|
||||
if (cls.IsNull()) {
|
||||
|
@ -11069,8 +11065,13 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) {
|
|||
selector = CallGetter(ident_pos, left, *ident);
|
||||
} else {
|
||||
// Static field access.
|
||||
selector =
|
||||
ParseStaticFieldAccess(cls, *ident, ident_pos, !is_cascade);
|
||||
selector = GenerateStaticFieldAccess(cls, *ident, ident_pos);
|
||||
ASSERT(selector != NULL);
|
||||
if (selector->IsLoadStaticFieldNode()) {
|
||||
selector->AsLoadStaticFieldNode()->set_is_deferred(is_deferred);
|
||||
} else if (selector->IsStaticGetterNode()) {
|
||||
selector->AsStaticGetterNode()->set_is_deferred(is_deferred);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (CurrentToken() == Token::kLBRACK) {
|
||||
|
@ -11466,8 +11467,8 @@ RawInstance* Parser::TryCanonicalize(const Instance& instance,
|
|||
// If the field is already initialized, return no ast (NULL).
|
||||
// Otherwise, if the field is constant, initialize the field and return no ast.
|
||||
// If the field is not initialized and not const, return the ast for the getter.
|
||||
AstNode* Parser::RunStaticFieldInitializer(const Field& field,
|
||||
intptr_t field_ref_pos) {
|
||||
StaticGetterNode* Parser::RunStaticFieldInitializer(const Field& field,
|
||||
intptr_t field_ref_pos) {
|
||||
ASSERT(field.is_static());
|
||||
const Class& field_owner = Class::ZoneHandle(Z, field.owner());
|
||||
const String& field_name = String::ZoneHandle(Z, field.name());
|
||||
|
@ -11752,16 +11753,22 @@ AstNode* Parser::ResolveIdentInCurrentLibraryScope(intptr_t ident_pos,
|
|||
} else if (obj.IsField()) {
|
||||
const Field& field = Field::Cast(obj);
|
||||
ASSERT(field.is_static());
|
||||
return GenerateStaticFieldLookup(field, ident_pos);
|
||||
AstNode* get_field = GenerateStaticFieldLookup(field, ident_pos);
|
||||
if (get_field->IsStaticGetterNode()) {
|
||||
get_field->AsStaticGetterNode()->set_owner(library_);
|
||||
}
|
||||
return get_field;
|
||||
} else if (obj.IsFunction()) {
|
||||
const Function& func = Function::Cast(obj);
|
||||
ASSERT(func.is_static());
|
||||
if (func.IsGetterFunction() || func.IsSetterFunction()) {
|
||||
return new(Z) StaticGetterNode(ident_pos,
|
||||
/* receiver */ NULL,
|
||||
Class::ZoneHandle(Z, func.Owner()),
|
||||
ident);
|
||||
|
||||
StaticGetterNode* getter =
|
||||
new(Z) StaticGetterNode(ident_pos,
|
||||
/* receiver */ NULL,
|
||||
Class::ZoneHandle(Z, func.Owner()),
|
||||
ident);
|
||||
getter->set_owner(library_);
|
||||
return getter;
|
||||
} else {
|
||||
return new(Z) PrimaryNode(ident_pos, Function::ZoneHandle(Z, func.raw()));
|
||||
}
|
||||
|
@ -11796,7 +11803,7 @@ AstNode* Parser::ResolveIdentInPrefixScope(intptr_t ident_pos,
|
|||
// Private names are not exported by libraries. The name mangling
|
||||
// of private names with a library-specific suffix usually ensures
|
||||
// that _x in library A is not found when looked up from library B.
|
||||
// In the pathological case where a library includes itself with
|
||||
// In the pathological case where a library imports itself with
|
||||
// a prefix, the name mangling would not help in hiding the private
|
||||
// name, so we need to explicitly reject private names here.
|
||||
return NULL;
|
||||
|
@ -11833,6 +11840,7 @@ AstNode* Parser::ResolveIdentInPrefixScope(intptr_t ident_pos,
|
|||
get_field->AsLoadStaticFieldNode()->set_is_deferred(is_deferred);
|
||||
} else if (get_field->IsStaticGetterNode()) {
|
||||
get_field->AsStaticGetterNode()->set_is_deferred(is_deferred);
|
||||
get_field->AsStaticGetterNode()->set_owner(prefix);
|
||||
}
|
||||
return get_field;
|
||||
} else if (obj.IsFunction()) {
|
||||
|
@ -11840,11 +11848,12 @@ AstNode* Parser::ResolveIdentInPrefixScope(intptr_t ident_pos,
|
|||
ASSERT(func.is_static());
|
||||
if (func.IsGetterFunction() || func.IsSetterFunction()) {
|
||||
StaticGetterNode* getter = new(Z) StaticGetterNode(
|
||||
ident_pos,
|
||||
/* receiver */ NULL,
|
||||
Class::ZoneHandle(Z, func.Owner()),
|
||||
ident);
|
||||
ident_pos,
|
||||
/* receiver */ NULL,
|
||||
Class::ZoneHandle(Z, func.Owner()),
|
||||
ident);
|
||||
getter->set_is_deferred(is_deferred);
|
||||
getter->set_owner(prefix);
|
||||
return getter;
|
||||
} else {
|
||||
PrimaryNode* primary = new(Z) PrimaryNode(
|
||||
|
|
|
@ -381,8 +381,8 @@ class Parser : public ValueObject {
|
|||
void CheckRecursiveInvocation();
|
||||
|
||||
const Instance& EvaluateConstExpr(intptr_t expr_pos, AstNode* expr);
|
||||
AstNode* RunStaticFieldInitializer(const Field& field,
|
||||
intptr_t field_ref_pos);
|
||||
StaticGetterNode* RunStaticFieldInitializer(const Field& field,
|
||||
intptr_t field_ref_pos);
|
||||
RawObject* EvaluateConstConstructorCall(const Class& type_class,
|
||||
const TypeArguments& type_arguments,
|
||||
const Function& constructor,
|
||||
|
@ -711,10 +711,9 @@ class Parser : public ValueObject {
|
|||
AstNode* ParseClosureCall(AstNode* closure);
|
||||
AstNode* GenerateStaticFieldLookup(const Field& field,
|
||||
intptr_t ident_pos);
|
||||
AstNode* ParseStaticFieldAccess(const Class& cls,
|
||||
const String& field_name,
|
||||
intptr_t ident_pos,
|
||||
bool consume_cascades);
|
||||
AstNode* GenerateStaticFieldAccess(const Class& cls,
|
||||
const String& field_name,
|
||||
intptr_t ident_pos);
|
||||
|
||||
LocalVariable* LookupLocalScope(const String& ident);
|
||||
void CheckInstanceFieldAccess(intptr_t field_pos, const String& field_name);
|
||||
|
|
|
@ -6,3 +6,5 @@ library GetterSetterInLib;
|
|||
|
||||
get foo => 42;
|
||||
set foo(a) {}
|
||||
|
||||
get bar => 77;
|
||||
|
|
7
tests/language/getter_setter_in_lib2.dart
Normal file
7
tests/language/getter_setter_in_lib2.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library GetterSetterInLib2;
|
||||
|
||||
set bar(a) { }
|
11
tests/language/getter_setter_in_lib3.dart
Normal file
11
tests/language/getter_setter_in_lib3.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library GetterSetterInLib3;
|
||||
|
||||
var _f = 33;
|
||||
|
||||
set bar(a) { _f = a; }
|
||||
|
||||
get bar => _f;
|
|
@ -5,9 +5,19 @@
|
|||
library GetterSetterInLibTest;
|
||||
import "package:expect/expect.dart";
|
||||
import 'getter_setter_in_lib.dart';
|
||||
import 'getter_setter_in_lib2.dart';
|
||||
import 'getter_setter_in_lib3.dart' as L3;
|
||||
|
||||
main() {
|
||||
Expect.equals(42, foo);
|
||||
foo = 43;
|
||||
Expect.equals(42, foo);
|
||||
|
||||
Expect.equals(77, bar);
|
||||
bar = 43;
|
||||
Expect.equals(77, bar);
|
||||
|
||||
Expect.equals(L3.bar, 33);
|
||||
L3.bar = 44;
|
||||
Expect.equals(L3.bar, 44);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ deferred_inlined_test: Fail # Issue 17523
|
|||
deferred_optimized_test: Fail # Issue 17523
|
||||
regress_22443_test: Fail # Issue 17523
|
||||
enum_mirror_test: Skip # Issue 11511.
|
||||
getter_setter_in_lib_test: Fail # Issue 23288
|
||||
|
||||
override_inheritance_mixed_test/08: Fail # Issue 18124
|
||||
override_inheritance_mixed_test/09: Fail # Issue 18124
|
||||
|
|
|
@ -13,6 +13,7 @@ await_test: CompileTimeError # Issue 22052
|
|||
async_await_test/02: CompileTimeError # Issue 22052
|
||||
regress_17382_test: Skip # don't care about the static warning.
|
||||
regress_23038_test/01: Skip # Issue 23038
|
||||
getter_setter_in_lib_test: Fail # issue 23286
|
||||
|
||||
issue13179_test: CompileTimeError # Issue 13179
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ enum_syntax_test/05: Fail # 21649
|
|||
enum_syntax_test/06: Fail # 21649
|
||||
|
||||
regress_17382_test: Skip # don't care about the static warning.
|
||||
getter_setter_in_lib_test: Fail # issue 23286
|
||||
|
||||
# Test issue 12694 (was analyzer issue), (1) when "abstract" is import prefix using it as type is warning; (2) currently analyzer resolves prefix as field (don't ask)
|
||||
built_in_identifier_prefix_test: CompileTimeError # Issue 12694
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
sync_generator2_test/07: MissingCompileTimeError # Issue 22324
|
||||
sync_generator2_test/08: MissingCompileTimeError # Issue 22324
|
||||
sync_generator2_test/10: MissingCompileTimeError # Issue 22324
|
||||
getter_setter_in_lib_test: Fail # Issue 23288
|
||||
|
||||
async_star_test/02: RuntimeError # 22853
|
||||
async_star_test/05: RuntimeError, Timeout
|
||||
|
|
Loading…
Reference in a new issue