100class ExpressionAnalyzer {
102 using MaybeExpr = std::optional<Expr<SomeType>>;
106 : context_{sc}, foldingContext_{fc} {}
107 ExpressionAnalyzer(
const ExpressionAnalyzer &) =
default;
110 bool inWhereBody()
const {
return inWhereBody_; }
111 void set_inWhereBody(
bool yes =
true) { inWhereBody_ = yes; }
112 bool inDataStmtObject()
const {
return inDataStmtObject_; }
113 void set_inDataStmtObject(
bool yes =
true) { inDataStmtObject_ = yes; }
115 FoldingContext &GetFoldingContext()
const {
return foldingContext_; }
118 return foldingContext_.messages();
122 return GetContextualMessages().Say(std::forward<A>(args)...);
124 template <
typename FeatureOrUsageWarning,
typename... A>
127 return context_.Warn(warning, at, std::forward<A>(args)...);
129 template <
typename FeatureOrUsageWarning,
typename... A>
132 warning, GetContextualMessages().at(), std::forward<A>(args)...);
135 template <
typename T,
typename... A>
137 return Say(parser::FindSourceLocation(parsed), std::forward<A>(args)...);
140 int GetDefaultKind(common::TypeCategory);
141 DynamicType GetDefaultKindOfType(common::TypeCategory);
144 bool CheckIntrinsicKind(TypeCategory, std::int64_t kind);
145 bool CheckIntrinsicSize(TypeCategory, std::int64_t size);
156 return common::ScopedSet(useSavedTypedExprs_,
false);
160 const std::optional<parser::KindSelector> &);
172 return Analyze(x.value());
174 template <
typename A> MaybeExpr Analyze(
const std::optional<A> &x) {
184 auto result{Analyze(x.thing)};
186 if (
int rank{result->Rank()}; rank != 0) {
187 SayAt(x,
"Must be a scalar value, but is a rank-%d array"_err_en_US,
197 GetFoldingContext().messages().SetLocation(FindSourceLocation(x))};
198 auto result{Analyze(x.thing)};
200 *result = Fold(std::move(*result));
201 if (!IsConstantExpr(*result)) {
202 SayAt(x,
"Must be a constant value"_err_en_US);
207 SetExpr(x, common::Clone(*result));
213 auto result{Analyze(x.thing)};
214 if (!EnforceTypeConstraint(
215 parser::FindSourceLocation(x), result, TypeCategory::Integer)) {
222 auto result{Analyze(x.thing)};
223 if (!EnforceTypeConstraint(
224 parser::FindSourceLocation(x), result, TypeCategory::Logical)) {
231 auto result{Analyze(x.thing)};
232 if (!EnforceTypeConstraint(parser::FindSourceLocation(x), result,
233 TypeCategory::Character,
true )) {
242 return Analyze<parser::DataRef>(dr);
249 MaybeExpr Analyze(
const parser::InitialDataTarget &);
250 MaybeExpr Analyze(
const parser::NullInit &);
253 std::optional<parser::StructureConstructor> * =
nullptr);
260 MaybeExpr Designate(
DataRef &&);
266 return common::ScopedSet(isWholeAssumedSizeArrayOk_, yes);
271 return common::ScopedSet(isAssumedTypeDummyOk_, yes);
275 int IntegerTypeSpecKind(
const parser::IntegerTypeSpec &);
280 return common::ScopedSet(isNullPointerOk_,
true);
291 MaybeExpr Analyze(
const parser::BOZLiteralConstant &);
292 MaybeExpr Analyze(
const parser::NamedConstant &);
299 MaybeExpr Analyze(
const parser::ArrayConstructor &);
304 MaybeExpr Analyze(
const parser::Expr::PercentLoc &);
324 template <
typename A> MaybeExpr Analyze(
const A &x) {
327 template <
typename... As> MaybeExpr Analyze(
const std::variant<As...> &u) {
328 return common::visit([&](
const auto &x) {
return Analyze(x); }, u);
332 int AnalyzeKindParam(
333 const std::optional<parser::KindParam> &,
int defaultKind);
334 template <
typename PARSED>
336 template <
typename TYPES, TypeCategory CAT,
typename PARSED>
337 MaybeExpr IntLiteralConstant(
const PARSED &,
bool isNegated =
false);
338 MaybeExpr AnalyzeString(std::string &&,
int kind);
339 std::optional<Expr<SubscriptInteger>> AsSubscript(MaybeExpr &&);
340 std::optional<Expr<SubscriptInteger>> TripletPart(
341 const std::optional<parser::Subscript> &);
342 std::optional<Subscript> AnalyzeSectionSubscript(
344 std::vector<Subscript> AnalyzeSectionSubscripts(
345 const std::list<parser::SectionSubscript> &);
346 std::optional<Component> CreateComponent(
DataRef &&,
const Symbol &,
348 MaybeExpr CompleteSubscripts(
ArrayRef &&);
349 MaybeExpr ApplySubscripts(
DataRef &&, std::vector<Subscript> &&);
350 bool CheckRanks(
const DataRef &);
351 bool CheckPolymorphic(
const DataRef &);
352 bool CheckDataRef(
const DataRef &);
353 std::optional<Expr<SubscriptInteger>> GetSubstringBound(
354 const std::optional<parser::ScalarIntExpr> &);
355 MaybeExpr AnalyzeDefinedOp(
359 struct CalleeAndArguments {
363 std::variant<ProcedureDesignator, SymbolRef> u;
364 ActualArguments arguments;
367 std::optional<CalleeAndArguments> AnalyzeProcedureComponentRef(
369 std::optional<characteristics::Procedure> CheckCall(
371 using AdjustActuals =
372 std::optional<std::function<bool(
const Symbol &, ActualArguments &)>>;
374 struct GenericResolution {
375 const Symbol *specific{
nullptr};
376 bool failedDueToAmbiguity{
false};
377 SymbolVector tried{};
379 GenericResolution ResolveGeneric(
const Symbol &,
const ActualArguments &,
380 const AdjustActuals &,
bool isSubroutine, SymbolVector &&tried,
381 bool mightBeStructureConstructor =
false);
382 void EmitGenericResolutionError(
const Symbol &,
bool dueToNullActuals,
383 bool isSubroutine,
const ActualArguments &,
const SymbolVector &,
384 const AdjustActuals &);
385 const Symbol &AccessSpecific(
387 std::optional<CalleeAndArguments> GetCalleeAndArguments(
const parser::Name &,
388 ActualArguments &&,
bool isSubroutine =
false,
389 bool mightBeStructureConstructor =
false);
390 std::optional<CalleeAndArguments> GetCalleeAndArguments(
392 bool isSubroutine,
bool mightBeStructureConstructor =
false);
396 bool defaultKind =
false);
397 MaybeExpr MakeFunctionRef(
400 template <
typename T> T Fold(T &&expr) {
401 return evaluate::Fold(foldingContext_, std::move(expr));
404 MaybeExpr AnalyzeComplex(MaybeExpr &&re, MaybeExpr &&im,
const char *what);
409 struct ComponentSpec {
410 ComponentSpec() =
default;
411 ComponentSpec(ComponentSpec &&) =
default;
413 bool hasKeyword{
false};
414 const Symbol *keywordSymbol{
nullptr};
421 const std::list<parser::ComponentSpec> &);
423 MaybeExpr IterativelyAnalyzeSubexpressions(
const parser::Expr &);
427 std::map<parser::CharBlock, int> impliedDos_;
429 std::pair<parser::CharBlock, evaluate::characteristics::Procedure>>
431 bool isWholeAssumedSizeArrayOk_{
false};
432 bool isNullPointerOk_{
false};
433 bool isAssumedTypeDummyOk_{
false};
434 bool useSavedTypedExprs_{
true};
435 bool inWhereBody_{
false};
436 bool inDataStmtObject_{
false};
437 bool inDataStmtConstant_{
false};
438 bool inStmtFunctionDefinition_{
false};
439 bool iterativelyAnalyzingSubexpressions_{
false};
440 friend class ArgumentAnalyzer;
488 template <
typename A>
bool Pre(
const A &) {
return true; }
489 template <
typename A>
void Post(
const A &) {}
490 bool Walk(
const parser::Program &);
493 AnalyzeAndNoteUses(x);
497 AnalyzeAndNoteUses(x);
501 exprAnalyzer_.Analyze(x);
505 exprAnalyzer_.Analyze(x);
509 AnalyzeAndNoteUses(x,
true);
513 AnalyzeAndNoteUses(x,
true);
518 std::get<std::optional<parser::ScalarIntConstantExpr>>(x.t)};
519 return !init || !parser::IsBOZLiteral(*init);
526 AnalyzeAndNoteUses(x);
530 AnalyzeAndNoteUses(x);
534 AnalyzeAndNoteUses(x);
541 exprAnalyzer_.set_inWhereBody(InWhereBody());
546 exprAnalyzer_.set_inWhereBody(InWhereBody());
550 exprAnalyzer_.set_inWhereBody(InWhereBody());
555 exprAnalyzer_.set_inWhereBody(InWhereBody());
561 inComponentDefStmt_ =
true;
571 return !inComponentDefStmt_ ||
572 std::holds_alternative<
573 std::list<common::Indirection<parser::DataStmtValue>>>(x.u);
577 AnalyzeAndNoteUses(x);
581 AnalyzeAndNoteUses(x);
585 AnalyzeAndNoteUses(x);
589 AnalyzeAndNoteUses(x);
593 AnalyzeAndNoteUses(x);
598 template <
typename A>
599 void AnalyzeAndNoteUses(
600 const A &x, [[maybe_unused]]
bool isDefinition =
false) {
601 exprAnalyzer_.Analyze(x);
603 if (x.typedExpr && x.typedExpr->v) {
604 NoteUsedSymbols(context_, *x.typedExpr->v, isDefinition);
608 context_.NoteUsedSymbols(
609 evaluate::CollectUsedSymbolValues(context_, *x.typedCall));
612 if (x.typedAssignment && x.typedAssignment->v) {
613 context_.NoteUsedSymbols(
614 evaluate::CollectUsedSymbolValues(context_, *x.typedAssignment->v));
618 bool InWhereBody()
const {
return whereDepth_ > 0; }
623 bool inComponentDefStmt_{
false};