struct Variable {
UNION_CLASS_BOILERPLATE(Variable);
mutable TypedExpr typedExpr;
- parser::CharBlock GetSource() const;
+ CharBlock GetSource() const;
std::variant<common::Indirection<Designator>,
common::Indirection<FunctionReference>>
u;
expr.u);
}
+// Apply GetUltimate(), then if the symbol is a generic procedure shadowing a
+// specific procedure of the same name, return it instead.
+const Symbol &BypassGeneric(const Symbol &);
+
using SomeExpr = evaluate::Expr<evaluate::SomeType>;
bool ExprHasTypeCategory(
static_assert(T::category == TypeCategory::Integer ||
T::category == TypeCategory::Real ||
T::category == TypeCategory::Character);
- using Element = Scalar<T>; // pmk: was typename Constant<T>::Element;
+ using Element = Scalar<T>;
std::optional<ConstantSubscript> dim;
if (std::optional<Constant<T>> array{
ProcessReductionArgs<T>(context, ref.arguments(), dim, identity,
// or procedure pointer reference in a ProcedureDesignator.
MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) {
const Symbol &last{ref.GetLastSymbol()};
- const Symbol &symbol{last.GetUltimate()};
+ const Symbol &symbol{BypassGeneric(last).GetUltimate()};
if (semantics::IsProcedure(symbol)) {
if (auto *component{std::get_if<Component>(&ref.u)}) {
return Expr<SomeType>{ProcedureDesignator{std::move(*component)}};
} else if (!std::holds_alternative<SymbolRef>(ref.u)) {
DIE("unexpected alternative in DataRef");
} else if (!symbol.attrs().test(semantics::Attr::INTRINSIC)) {
- return Expr<SomeType>{ProcedureDesignator{symbol}};
+ if (symbol.has<semantics::GenericDetails>()) {
+ Say("'%s' is not a specific procedure"_err_en_US, symbol.name());
+ } else {
+ return Expr<SomeType>{ProcedureDesignator{symbol}};
+ }
} else if (auto interface{context_.intrinsics().IsSpecificIntrinsicFunction(
symbol.name().ToString())}) {
SpecificIntrinsic intrinsic{
std::optional<ActualArgument> actual;
std::visit(common::visitors{
[&](const common::Indirection<parser::Expr> &x) {
- // TODO: Distinguish & handle procedure name and
- // proc-component-ref
actual = AnalyzeExpr(x.value());
},
[&](const parser::AltReturnSpec &label) {
auto &details{generic.get<GenericDetails>()};
UnorderedSymbolSet symbolsSeen;
for (const Symbol &symbol : details.specificProcs()) {
- symbolsSeen.insert(symbol);
+ symbolsSeen.insert(symbol.GetUltimate());
}
auto range{specificProcs_.equal_range(&generic)};
for (auto it{range.first}; it != range.second; ++it) {
Say(*name, "Procedure '%s' not found"_err_en_US);
continue;
}
- if (symbol == &generic) {
- if (auto *specific{generic.get<GenericDetails>().specific()}) {
- symbol = specific;
- }
- }
- const Symbol &ultimate{symbol->GetUltimate()};
+ const Symbol &specific{BypassGeneric(*symbol)};
+ const Symbol &ultimate{specific.GetUltimate()};
if (!ultimate.has<SubprogramDetails>() &&
!ultimate.has<SubprogramNameDetails>()) {
Say(*name, "'%s' is not a subprogram"_err_en_US);
}
}
}
- if (!symbolsSeen.insert(ultimate).second) {
- if (symbol == &ultimate) {
- Say(name->source,
- "Procedure '%s' is already specified in generic '%s'"_err_en_US,
- name->source, MakeOpName(generic.name()));
- } else {
- Say(name->source,
- "Procedure '%s' from module '%s' is already specified in generic '%s'"_err_en_US,
- ultimate.name(), ultimate.owner().GetName().value(),
- MakeOpName(generic.name()));
- }
- continue;
+ if (symbolsSeen.insert(ultimate).second /*true if added*/) {
+ // When a specific procedure is a USE association, that association
+ // is saved in the generic's specifics, not its ultimate symbol,
+ // so that module file output of interfaces can distinguish them.
+ details.AddSpecificProc(specific, name->source);
+ } else if (&specific == &ultimate) {
+ Say(name->source,
+ "Procedure '%s' is already specified in generic '%s'"_err_en_US,
+ name->source, MakeOpName(generic.name()));
+ } else {
+ Say(name->source,
+ "Procedure '%s' from module '%s' is already specified in generic '%s'"_err_en_US,
+ ultimate.name(), ultimate.owner().GetName().value(),
+ MakeOpName(generic.name()));
}
- details.AddSpecificProc(*symbol, name->source);
}
specificProcs_.erase(range.first, range.second);
}
return nullptr;
}
+const Symbol &BypassGeneric(const Symbol &symbol) {
+ const Symbol &ultimate{symbol.GetUltimate()};
+ if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) {
+ if (const Symbol * specific{generic->specific()}) {
+ return *specific;
+ }
+ }
+ return symbol;
+}
+
bool ExprHasTypeCategory(
const SomeExpr &expr, const common::TypeCategory &type) {
auto dynamicType{expr.GetType()};
lenParameterKind_; // pointer to rank-1 array of INTEGER(1)
// This array of local data components includes the parent component.
- // Components are in alphabetic order.
- // TODO pmk: fix to be "component order"
+ // Components are in component order, not collation order of their names.
// It does not include procedure pointer components.
StaticDescriptor<1, true>
component_; // TYPE(COMPONENT), POINTER, DIMENSION(:), CONTIGUOUS