bool receiver_can_be_pointer = (expr->type()->points_to() != NULL
|| expr->is_addressable());
+ std::vector<const Named_type*> seen;
bool is_method = false;
bool found_pointer_method = false;
std::string ambig1;
std::string ambig2;
- if (Type::find_field_or_method(type, name, receiver_can_be_pointer, NULL,
- &is_method, &found_pointer_method,
- &ambig1, &ambig2))
+ if (Type::find_field_or_method(type, name, receiver_can_be_pointer,
+ &seen, NULL, &is_method,
+ &found_pointer_method, &ambig1, &ambig2))
{
Expression* ret;
if (!is_method)
// ambiguity. If a method is found, sets *IS_METHOD to true;
// otherwise, if a field is found, set it to false. If
// RECEIVER_CAN_BE_POINTER is false, then the receiver is a value
-// whose address can not be taken. When returning false, this sets
-// *FOUND_POINTER_METHOD if we found a method we couldn't use because
-// it requires a pointer. LEVEL is used for recursive calls, and can
-// be NULL for a non-recursive call. When this function returns false
-// because it finds that the name is ambiguous, it will store a path
-// to the ambiguous names in *AMBIG1 and *AMBIG2. If the name is not
-// found at all, *AMBIG1 and *AMBIG2 will be unchanged.
+// whose address can not be taken. SEEN is used to avoid infinite
+// recursion on invalid types.
+
+// When returning false, this sets *FOUND_POINTER_METHOD if we found a
+// method we couldn't use because it requires a pointer. LEVEL is
+// used for recursive calls, and can be NULL for a non-recursive call.
+// When this function returns false because it finds that the name is
+// ambiguous, it will store a path to the ambiguous names in *AMBIG1
+// and *AMBIG2. If the name is not found at all, *AMBIG1 and *AMBIG2
+// will be unchanged.
// This function just returns whether or not there is a field or
// method, and whether it is a field or method. It doesn't build an
Type::find_field_or_method(const Type* type,
const std::string& name,
bool receiver_can_be_pointer,
+ std::vector<const Named_type*>* seen,
int* level,
bool* is_method,
bool* found_pointer_method,
// else.
*found_pointer_method = true;
}
+
+ for (std::vector<const Named_type*>::const_iterator p = seen->begin();
+ p != seen->end();
+ ++p)
+ {
+ if (*p == nt)
+ {
+ // We've already seen this type when searching for methods.
+ return false;
+ }
+ }
}
// Interface types can have methods.
if (fields == NULL)
return false;
+ if (nt != NULL)
+ seen->push_back(nt);
+
int found_level = 0;
bool found_is_method = false;
std::string found_ambig1;
if (pf->field_name() == name)
{
*is_method = false;
+ if (nt != NULL)
+ seen->pop_back();
return true;
}
bool subfound = Type::find_field_or_method(fnt,
name,
receiver_can_be_pointer,
+ seen,
&sublevel,
&sub_is_method,
found_pointer_method,
// FOUND_AMBIG2 are not empty. If we found the field, FOUND_LEVEL
// is not 0 and FOUND_AMBIG1 and FOUND_AMBIG2 are empty.
+ if (nt != NULL)
+ seen->pop_back();
+
if (found_level == 0)
return false;
else if (!found_ambig1.empty())
static bool
find_field_or_method(const Type* type, const std::string& name,
bool receiver_can_be_pointer,
- int* level, bool* is_method,
- bool* found_pointer_method,
+ std::vector<const Named_type*>*, int* level,
+ bool* is_method, bool* found_pointer_method,
std::string* ambig1, std::string* ambig2);
// Get a tree for a type without looking in the hash table for