using common::RelationalOperator;
using IntrinsicOperator = parser::DefinedOperator::IntrinsicOperator;
+static constexpr const char *operatorPrefix{"operator("};
+
static GenericKind MapIntrinsicOperator(IntrinsicOperator);
Symbol *Resolve(const parser::Name &name, Symbol *symbol) {
return false;
}
+template <typename E>
+std::forward_list<std::string> GetOperatorNames(
+ const SemanticsContext &context, E opr) {
+ std::forward_list<std::string> result;
+ for (const char *name : context.languageFeatures().GetNames(opr)) {
+ result.emplace_front(std::string{operatorPrefix} + name + ')');
+ }
+ return result;
+}
+
+std::forward_list<std::string> GetAllNames(
+ const SemanticsContext &context, const SourceName &name) {
+ std::string str{name.ToString()};
+ if (!name.empty() && name.end()[-1] == ')' &&
+ name.ToString().rfind(std::string{operatorPrefix}, 0) == 0) {
+ for (int i{0}; i != common::LogicalOperator_enumSize; ++i) {
+ auto names{GetOperatorNames(context, LogicalOperator{i})};
+ if (std::find(names.begin(), names.end(), str) != names.end()) {
+ return names;
+ }
+ }
+ for (int i{0}; i != common::RelationalOperator_enumSize; ++i) {
+ auto names{GetOperatorNames(context, RelationalOperator{i})};
+ if (std::find(names.begin(), names.end(), str) != names.end()) {
+ return names;
+ }
+ }
+ }
+ return {str};
+}
+
bool IsLogicalConstant(
const SemanticsContext &context, const SourceName &name) {
std::string str{name.ToString()};
(str == ".t" || str == ".f."));
}
-// The operators <, <=, >, >=, ==, and /= always have the same interpretations
-// as the operators .LT., .LE., .GT., .GE., .EQ., and .NE., respectively.
-std::forward_list<std::string> GenericSpecInfo::GetAllNames(
- SemanticsContext &context) const {
- auto getNames{[&](auto opr) {
- std::forward_list<std::string> result;
- for (const char *name : context.languageFeatures().GetNames(opr)) {
- result.emplace_front("operator("s + name + ')');
- }
- return result;
- }};
- return std::visit(
- common::visitors{[&](const LogicalOperator &x) { return getNames(x); },
- [&](const RelationalOperator &x) { return getNames(x); },
- [&](const auto &) -> std::forward_list<std::string> {
- return {symbolName_.value().ToString()};
- }},
- kind_.u);
-}
-
-Symbol *GenericSpecInfo::FindInScope(
- SemanticsContext &context, const Scope &scope) const {
- for (const auto &name : GetAllNames(context)) {
- auto iter{scope.find(SourceName{name})};
- if (iter != scope.end()) {
- return &*iter->second;
- }
- }
- return nullptr;
-}
-
void GenericSpecInfo::Resolve(Symbol *symbol) const {
if (symbol) {
if (auto *details{symbol->detailsIf<GenericDetails>()}) {
x.u);
}
+llvm::raw_ostream &operator<<(
+ llvm::raw_ostream &os, const GenericSpecInfo &info) {
+ os << "GenericSpecInfo: kind=" << info.kind_.ToString();
+ os << " parseName="
+ << (info.parseName_ ? info.parseName_->ToString() : "null");
+ os << " symbolName="
+ << (info.symbolName_ ? info.symbolName_->ToString() : "null");
+ return os;
+}
+
// parser::DefinedOperator::IntrinsicOperator -> GenericKind
static GenericKind MapIntrinsicOperator(IntrinsicOperator op) {
switch (op) {
// Search for name only in scope, not in enclosing scopes.
Symbol *FindInScope(const Scope &, const parser::Name &);
Symbol *FindInScope(const Scope &, const SourceName &);
+ template <typename T> Symbol *FindInScope(const T &name) {
+ return FindInScope(currScope(), name);
+ }
// Search for name in a derived type scope and its parents.
Symbol *FindInTypeOrParents(const Scope &, const parser::Name &);
Symbol *FindInTypeOrParents(const parser::Name &);
const SourceName &name, const Attrs &attrs, D &&details) {
// Note: don't use FindSymbol here. If this is a derived type scope,
// we want to detect whether the name is already declared as a component.
- auto *symbol{FindInScope(currScope(), name)};
+ auto *symbol{FindInScope(name)};
if (!symbol) {
symbol = &MakeSymbol(name, attrs);
symbol->set_details(std::move(details));
return symbol;
}
Symbol &ScopeHandler::CopySymbol(const SourceName &name, const Symbol &symbol) {
- CHECK(!FindInScope(currScope(), name));
+ CHECK(!FindInScope(name));
return MakeSymbol(currScope(), name, symbol.attrs());
}
return Resolve(name, FindInScope(scope, name.source));
}
Symbol *ScopeHandler::FindInScope(const Scope &scope, const SourceName &name) {
- if (auto it{scope.find(name)}; it != scope.end()) {
- return &*it->second;
- } else {
- return nullptr;
+ // all variants of names, e.g. "operator(.ne.)" for "operator(/=)"
+ for (const std::string &n : GetAllNames(context(), name)) {
+ auto it{scope.find(SourceName{n})};
+ if (it != scope.end()) {
+ return &*it->second;
+ }
}
+ return nullptr;
}
// Find a component or type parameter by name in a derived type or its parents.
!symbol->attrs().test(Attr::INTRINSIC) &&
!symbol->has<MiscDetails>() && useNames.count(name) == 0) {
SourceName location{x.moduleName.source};
- if (auto *localSymbol{FindInScope(currScope(), name)}) {
+ if (auto *localSymbol{FindInScope(name)}) {
DoAddUse(location, localSymbol->name(), *localSymbol, *symbol);
} else {
DoAddUse(location, location, CopySymbol(name, *symbol), *symbol);
generic1.CopyFrom(generic2);
}
EraseSymbol(localSymbol);
- MakeSymbol(
- localSymbol.name(), localUltimate.attrs(), std::move(generic1));
+ MakeSymbol(localSymbol.name(), localSymbol.attrs(), std::move(generic1));
} else {
ConvertToUseError(localSymbol, location, *useModuleScope_);
}
void ModuleVisitor::AddUse(const GenericSpecInfo &info) {
if (useModuleScope_) {
const auto &name{info.symbolName()};
- auto rename{
- AddUse(name, name, info.FindInScope(context(), *useModuleScope_))};
+ auto rename{AddUse(name, name, FindInScope(*useModuleScope_, name))};
info.Resolve(rename.use);
}
}
// Create a symbol in genericSymbol_ for this GenericSpec.
bool InterfaceVisitor::Pre(const parser::GenericSpec &x) {
- if (auto *symbol{GenericSpecInfo{x}.FindInScope(context(), currScope())}) {
+ if (auto *symbol{FindInScope(GenericSpecInfo{x}.symbolName())}) {
SetGenericSymbol(*symbol);
}
return false;
if (attr == Attr::INTRINSIC && !IsIntrinsic(name.source, std::nullopt)) {
Say(name.source, "'%s' is not a known intrinsic procedure"_err_en_US);
}
- auto *symbol{FindInScope(currScope(), name)};
+ auto *symbol{FindInScope(name)};
if (attr == Attr::ASYNCHRONOUS || attr == Attr::VOLATILE) {
// these can be set on a symbol that is host-assoc or use-assoc
if (!symbol &&
CHECK(currScope().IsDerivedType());
for (auto &declaration : tbps.declarations) {
auto &bindingName{std::get<parser::Name>(declaration.t)};
- if (Symbol * binding{FindInScope(currScope(), bindingName)}) {
+ if (Symbol * binding{FindInScope(bindingName)}) {
if (auto *details{binding->detailsIf<ProcBindingDetails>()}) {
const Symbol *procedure{FindSubprogram(details->symbol())};
if (!CanBeTypeBoundProc(procedure)) {
SourceName symbolName{info.symbolName()};
bool isPrivate{accessSpec ? accessSpec->v == parser::AccessSpec::Kind::Private
: derivedTypeInfo_.privateBindings};
- auto *genericSymbol{info.FindInScope(context(), currScope())};
+ auto *genericSymbol{FindInScope(symbolName)};
if (genericSymbol) {
if (!genericSymbol->has<GenericDetails>()) {
genericSymbol = nullptr; // MakeTypeSymbol will report the error below
} else {
// look in parent types:
Symbol *inheritedSymbol{nullptr};
- for (const auto &name : info.GetAllNames(context())) {
+ for (const auto &name : GetAllNames(context(), symbolName)) {
inheritedSymbol = currScope().FindComponent(SourceName{name});
if (inheritedSymbol) {
break;
}
const auto &groupName{std::get<parser::Name>(x.t)};
- auto *groupSymbol{FindInScope(currScope(), groupName)};
+ auto *groupSymbol{FindInScope(groupName)};
if (!groupSymbol || !groupSymbol->has<NamelistDetails>()) {
groupSymbol = &MakeSymbol(groupName, std::move(details));
groupSymbol->ReplaceName(groupName.source);
void DeclarationVisitor::CheckSaveStmts() {
for (const SourceName &name : saveInfo_.entities) {
- auto *symbol{FindInScope(currScope(), name)};
+ auto *symbol{FindInScope(name)};
if (!symbol) {
// error was reported
} else if (saveInfo_.saveAll) {
void ConstructVisitor::Post(const parser::CoarrayAssociation &x) {
const auto &decl{std::get<parser::CodimensionDecl>(x.t)};
const auto &name{std::get<parser::Name>(decl.t)};
- if (auto *symbol{FindInScope(currScope(), name)}) {
+ if (auto *symbol{FindInScope(name)}) {
const auto &selector{std::get<parser::Selector>(x.t)};
if (auto sel{ResolveSelector(selector)}) {
const Symbol *whole{UnwrapWholeSymbolDataRef(sel.expr)};
[=](const Indirection<parser::GenericSpec> &y) {
auto info{GenericSpecInfo{y.value()}};
const auto &symbolName{info.symbolName()};
- if (auto *symbol{info.FindInScope(context(), currScope())}) {
+ if (auto *symbol{FindInScope(symbolName)}) {
info.Resolve(&SetAccess(symbolName, accessAttr, symbol));
} else if (info.kind().IsName()) {
info.Resolve(&SetAccess(symbolName, accessAttr));
return;
}
GenericDetails genericDetails;
- if (Symbol * existing{info.FindInScope(context(), currScope())}) {
+ if (Symbol * existing{FindInScope(symbolName)}) {
if (existing->has<GenericDetails>()) {
info.Resolve(existing);
return; // already have generic, add to it
void ResolveNamesVisitor::CheckImport(
const SourceName &location, const SourceName &name) {
- if (auto *symbol{FindInScope(currScope(), name)}) {
+ if (auto *symbol{FindInScope(name)}) {
Say(location, "'%s' from host is not accessible"_err_en_US, name)
.Attach(symbol->name(), "'%s' is hidden by this entity"_en_US,
symbol->name());