[flang] Combine GenericDetails and GenericBindingDetails

`GenericDetails` and `GenericBindingDetails` were almost identical:
the former has optional data members to handle the case when a specific
procedure or derived type has the same name as the generic symbol.

Most places they are handled the same way so it simplifies things to
have only one type. In the case where we want to know if it is a generic
binding (e.g. in `mod-file.cc`) we can check the kind of scope that owns
the symbol.

Save name from the generic binding for better location of error messages.

Original-commit: flang-compiler/f18@f65a9edca2
Reviewed-on: https://github.com/flang-compiler/f18/pull/841
Tree-same-pre-rewrite: false
This commit is contained in:
Tim Keith 2019-11-22 12:52:23 -08:00
parent 701a9bd0e5
commit e2b939e5f3
5 changed files with 57 additions and 77 deletions

View File

@ -200,12 +200,20 @@ void ModFileWriter::PutSymbol(
[&](const DerivedTypeDetails &) { PutDerivedType(symbol); },
[&](const SubprogramDetails &) { PutSubprogram(symbol); },
[&](const GenericDetails &x) {
PutGeneric(symbol);
if (x.specific()) {
PutSymbol(typeBindings, *x.specific());
}
if (x.derivedType()) {
PutSymbol(typeBindings, *x.derivedType());
if (symbol.owner().IsDerivedType()) {
// generic binding
for (const Symbol &proc : x.specificProcs()) {
typeBindings << "generic::" << symbol.name() << "=>"
<< proc.name() << '\n';
}
} else {
PutGeneric(symbol);
if (x.specific()) {
PutSymbol(typeBindings, *x.specific());
}
if (x.derivedType()) {
PutSymbol(typeBindings, *x.derivedType());
}
}
},
[&](const UseDetails &) { PutUse(symbol); },
@ -228,12 +236,6 @@ void ModFileWriter::PutSymbol(
}
typeBindings << '\n';
},
[&](const GenericBindingDetails &x) {
for (const Symbol &proc : x.specificProcs()) {
typeBindings << "generic::" << symbol.name() << "=>"
<< proc.name() << '\n';
}
},
[&](const NamelistDetails &x) {
decls_ << "namelist/" << symbol.name();
char sep{'/'};

View File

@ -120,8 +120,6 @@ void GenericSpecInfo::Resolve(Symbol *symbol) const {
if (symbol) {
if (auto *details{symbol->detailsIf<GenericDetails>()}) {
details->set_kind(kind_);
} else if (auto *details{symbol->detailsIf<GenericBindingDetails>()}) {
details->set_kind(kind_);
}
if (parseName_) {
semantics::Resolve(*parseName_, symbol);

View File

@ -2488,7 +2488,7 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) {
name->source, generic.name());
continue;
}
details.add_specificProc(*symbol);
details.AddSpecificProc(*symbol, name->source);
}
specificProcs_.erase(range.first, range.second);
}
@ -2557,16 +2557,6 @@ void InterfaceVisitor::SayNotDistinguishable(
}
}
static GenericKind GetGenericKind(const Symbol &generic) {
return std::visit(
common::visitors{
[&](const GenericDetails &x) { return x.kind(); },
[&](const GenericBindingDetails &x) { return x.kind(); },
[](auto &) -> GenericKind { DIE("not a generic"); },
},
generic.details());
}
// Check that the specifics of this generic are distinguishable from each other
void InterfaceVisitor::CheckSpecificsAreDistinguishable(
Symbol &generic, const SymbolVector &specifics) {
@ -2574,7 +2564,7 @@ void InterfaceVisitor::CheckSpecificsAreDistinguishable(
if (specifics.size() < 2) {
return;
}
auto kind{GetGenericKind(generic)};
auto kind{generic.get<GenericDetails>().kind()};
auto distinguishable{kind.IsAssignment() || kind.IsOperator()
? evaluate::characteristics::DistinguishableOpOrAssign
: evaluate::characteristics::Distinguishable};
@ -2829,7 +2819,7 @@ Symbol &SubprogramVisitor::PushSubprogramScope(
MakeExternal(*symbol);
}
if (isGeneric()) {
GetGenericDetails().add_specificProc(*symbol);
GetGenericDetails().AddSpecificProc(*symbol, name.source);
}
implicitRules().set_inheritFromParent(false);
}
@ -3767,8 +3757,8 @@ void DeclarationVisitor::Post(const parser::TypeBoundProcedurePart &) {
SayWithDecl(*bindingName, *symbol, // C772
"'%s' is not the name of a specific binding of this type"_err_en_US);
} else {
auto &details{generic->get<GenericBindingDetails>()};
details.add_specificProc(*symbol);
generic->get<GenericDetails>().AddSpecificProc(
*symbol, bindingName->source);
}
}
genericBindings_.clear();
@ -3864,7 +3854,7 @@ bool DeclarationVisitor::Pre(const parser::TypeBoundGenericStmt &x) {
: derivedTypeInfo_.privateBindings};
auto *genericSymbol{info.FindInScope(context(), currScope())};
if (genericSymbol) {
if (!genericSymbol->has<GenericBindingDetails>()) {
if (!genericSymbol->has<GenericDetails>()) {
genericSymbol = nullptr; // MakeTypeSymbol will report the error below
}
} else {
@ -3876,14 +3866,14 @@ bool DeclarationVisitor::Pre(const parser::TypeBoundGenericStmt &x) {
break;
}
}
if (inheritedSymbol && inheritedSymbol->has<GenericBindingDetails>()) {
if (inheritedSymbol && inheritedSymbol->has<GenericDetails>()) {
CheckAccessibility(symbolName, isPrivate, *inheritedSymbol); // C771
}
}
if (genericSymbol) {
CheckAccessibility(symbolName, isPrivate, *genericSymbol); // C771
} else {
genericSymbol = MakeTypeSymbol(symbolName, GenericBindingDetails{});
genericSymbol = MakeTypeSymbol(symbolName, GenericDetails{});
if (!genericSymbol) {
return false;
}
@ -6118,7 +6108,7 @@ void ResolveNamesVisitor::FinishDerivedTypeDefinition(Scope &scope) {
}
for (auto &pair : scope) {
Symbol &comp{*pair.second};
if (const auto *details{comp.detailsIf<GenericBindingDetails>()}) {
if (const auto *details{comp.detailsIf<GenericDetails>()}) {
CheckSpecificsAreDistinguishable(comp, details->specificProcs());
}
}

View File

@ -150,6 +150,11 @@ UseErrorDetails &UseErrorDetails::add_occurrence(
GenericDetails::GenericDetails(const SymbolVector &specificProcs)
: specificProcs_{specificProcs} {}
void GenericDetails::AddSpecificProc(
const Symbol &proc, SourceName bindingName) {
specificProcs_.push_back(proc);
bindingNames_.push_back(bindingName);
}
void GenericDetails::set_specific(Symbol &specific) {
CHECK(!specific_);
CHECK(!derivedType_);
@ -214,7 +219,6 @@ std::string DetailsToString(const Details &details) {
[](const HostAssocDetails &) { return "HostAssoc"; },
[](const GenericDetails &) { return "Generic"; },
[](const ProcBindingDetails &) { return "ProcBinding"; },
[](const GenericBindingDetails &) { return "GenericBinding"; },
[](const NamelistDetails &) { return "Namelist"; },
[](const CommonBlockDetails &) { return "CommonBlockDetails"; },
[](const FinalProcDetails &) { return "FinalProc"; },
@ -437,10 +441,6 @@ std::ostream &operator<<(std::ostream &os, const Details &details) {
os << " => " << x.symbol().name();
DumpOptional(os, "passName", x.passName());
},
[&](const GenericBindingDetails &x) {
os << " =>";
DumpSymbolVector(os, x.specificProcs());
},
[&](const NamelistDetails &x) {
os << ':';
DumpSymbolVector(os, x.objects());

View File

@ -270,42 +270,6 @@ private:
SymbolRef symbol_; // procedure bound to; may be forward
};
// A GenericKind is one of: generic name, defined operator,
// defined assignment, intrinsic operator, or defined I/O.
struct GenericKind {
ENUM_CLASS(OtherKind, Name, DefinedOp, Assignment, Concat)
ENUM_CLASS(DefinedIo, // defined io
ReadFormatted, ReadUnformatted, WriteFormatted, WriteUnformatted)
GenericKind() : u{OtherKind::Name} {}
template<typename T> GenericKind(const T &x) { u = x; }
bool IsName() const { return Is(OtherKind::Name); }
bool IsAssignment() const { return Is(OtherKind::Assignment); }
bool IsDefinedOperator() const { return Is(OtherKind::DefinedOp); }
bool IsIntrinsicOperator() const;
bool IsOperator() const;
std::string ToString() const;
std::variant<OtherKind, common::NumericOperator, common::LogicalOperator,
common::RelationalOperator, DefinedIo>
u;
private:
template<typename T> bool Has() const { return std::holds_alternative<T>(u); }
bool Is(OtherKind) const;
};
class GenericBindingDetails {
public:
GenericBindingDetails() {}
GenericKind kind() const { return kind_; }
void set_kind(GenericKind kind) { kind_ = kind; }
const SymbolVector &specificProcs() const { return specificProcs_; }
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(proc); }
private:
GenericKind kind_;
SymbolVector specificProcs_;
};
class NamelistDetails {
public:
const SymbolVector &objects() const { return objects_; }
@ -400,6 +364,30 @@ private:
SymbolRef symbol_;
};
// A GenericKind is one of: generic name, defined operator,
// defined assignment, intrinsic operator, or defined I/O.
struct GenericKind {
ENUM_CLASS(OtherKind, Name, DefinedOp, Assignment, Concat)
ENUM_CLASS(DefinedIo, // defined io
ReadFormatted, ReadUnformatted, WriteFormatted, WriteUnformatted)
GenericKind() : u{OtherKind::Name} {}
template<typename T> GenericKind(const T &x) { u = x; }
bool IsName() const { return Is(OtherKind::Name); }
bool IsAssignment() const { return Is(OtherKind::Assignment); }
bool IsDefinedOperator() const { return Is(OtherKind::DefinedOp); }
bool IsIntrinsicOperator() const;
bool IsOperator() const;
std::string ToString() const;
std::variant<OtherKind, common::NumericOperator, common::LogicalOperator,
common::RelationalOperator, DefinedIo>
u;
private:
template<typename T> bool Has() const { return std::holds_alternative<T>(u); }
bool Is(OtherKind) const;
};
// A generic interface or type-bound generic.
class GenericDetails {
public:
GenericDetails() {}
@ -409,7 +397,8 @@ public:
void set_kind(GenericKind kind) { kind_ = kind; }
const SymbolVector &specificProcs() const { return specificProcs_; }
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(proc); }
const std::vector<SourceName> &bindingNames() const { return bindingNames_; }
void AddSpecificProc(const Symbol &, SourceName bindingName);
// specific and derivedType indicate a specific procedure or derived type
// with the same name as this generic. Only one of them may be set.
@ -435,6 +424,7 @@ private:
GenericKind kind_;
// all of the specific procedures for this generic
SymbolVector specificProcs_;
std::vector<SourceName> bindingNames_;
// a specific procedure with the same name as this generic, if any
Symbol *specific_{nullptr};
// a derived type with the same name as this generic, if any
@ -450,8 +440,8 @@ using Details = std::variant<UnknownDetails, MainProgramDetails, ModuleDetails,
SubprogramDetails, SubprogramNameDetails, EntityDetails,
ObjectEntityDetails, ProcEntityDetails, AssocEntityDetails,
DerivedTypeDetails, UseDetails, UseErrorDetails, HostAssocDetails,
GenericDetails, ProcBindingDetails, GenericBindingDetails, NamelistDetails,
CommonBlockDetails, FinalProcDetails, TypeParamDetails, MiscDetails>;
GenericDetails, ProcBindingDetails, NamelistDetails, CommonBlockDetails,
FinalProcDetails, TypeParamDetails, MiscDetails>;
std::ostream &operator<<(std::ostream &, const Details &);
std::string DetailsToString(const Details &);