@@ -178,7 +178,7 @@ class ArgumentAnalyzer {
178
178
}
179
179
// Find and return a user-defined assignment
180
180
std::optional<ProcedureRef> TryDefinedAssignment ();
181
- std::optional<ProcedureRef> GetDefinedAssignmentProc ();
181
+ std::optional<ProcedureRef> GetDefinedAssignmentProc (bool &isAmbiguous );
182
182
std::optional<DynamicType> GetType (std::size_t ) const ;
183
183
void Dump (llvm::raw_ostream &);
184
184
@@ -191,15 +191,16 @@ class ArgumentAnalyzer {
191
191
MaybeExpr AnalyzeExprOrWholeAssumedSizeArray (const parser::Expr &);
192
192
bool AreConformable () const ;
193
193
const Symbol *FindBoundOp (parser::CharBlock, int passIndex,
194
- const Symbol *&generic, bool isSubroutine);
194
+ const Symbol *&generic, bool isSubroutine, bool *isAmbiguous = nullptr );
195
195
void AddAssignmentConversion (
196
196
const DynamicType &lhsType, const DynamicType &rhsType);
197
197
bool OkLogicalIntegerAssignment (TypeCategory lhs, TypeCategory rhs);
198
198
int GetRank (std::size_t ) const ;
199
199
bool IsBOZLiteral (std::size_t i) const {
200
200
return evaluate::IsBOZLiteral (GetExpr (i));
201
201
}
202
- void SayNoMatch (const std::string &, bool isAssignment = false );
202
+ void SayNoMatch (
203
+ const std::string &, bool isAssignment = false , bool isAmbiguous = false );
203
204
std::string TypeAsFortran (std::size_t );
204
205
bool AnyUntypedOrMissingOperand ();
205
206
@@ -4781,7 +4782,9 @@ std::optional<ProcedureRef> ArgumentAnalyzer::TryDefinedAssignment() {
4781
4782
return std::nullopt; // user-defined assignment not allowed for these args
4782
4783
}
4783
4784
auto restorer{context_.GetContextualMessages ().SetLocation (source_)};
4784
- if (std::optional<ProcedureRef> procRef{GetDefinedAssignmentProc ()}) {
4785
+ bool isAmbiguous{false };
4786
+ if (std::optional<ProcedureRef> procRef{
4787
+ GetDefinedAssignmentProc (isAmbiguous)}) {
4785
4788
if (context_.inWhereBody () && !procRef->proc ().IsElemental ()) { // C1032
4786
4789
context_.Say (
4787
4790
" Defined assignment in WHERE must be elemental, but '%s' is not" _err_en_US,
@@ -4791,9 +4794,11 @@ std::optional<ProcedureRef> ArgumentAnalyzer::TryDefinedAssignment() {
4791
4794
return std::move (*procRef);
4792
4795
}
4793
4796
if (isDefined == Tristate::Yes) {
4794
- if (!lhsType || !rhsType || (lhsRank != rhsRank && rhsRank != 0 ) ||
4797
+ if (isAmbiguous || !lhsType || !rhsType ||
4798
+ (lhsRank != rhsRank && rhsRank != 0 ) ||
4795
4799
!OkLogicalIntegerAssignment (lhsType->category (), rhsType->category ())) {
4796
- SayNoMatch (" ASSIGNMENT(=)" , true );
4800
+ SayNoMatch (
4801
+ " ASSIGNMENT(=)" , /* isAssignment=*/ true , /* isAmbiguous=*/ isAmbiguous);
4797
4802
}
4798
4803
} else if (!fatalErrors_) {
4799
4804
CheckAssignmentConformance ();
@@ -4822,13 +4827,15 @@ bool ArgumentAnalyzer::OkLogicalIntegerAssignment(
4822
4827
return true ;
4823
4828
}
4824
4829
4825
- std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc () {
4830
+ std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc (
4831
+ bool &isAmbiguous) {
4826
4832
const Symbol *proc{nullptr };
4827
4833
bool isProcElemental{false };
4828
4834
std::optional<int > passedObjectIndex;
4829
4835
std::string oprNameString{" assignment(=)" };
4830
4836
parser::CharBlock oprName{oprNameString};
4831
4837
const auto &scope{context_.context ().FindScope (source_)};
4838
+ isAmbiguous = false ;
4832
4839
{
4833
4840
auto restorer{context_.GetContextualMessages ().DiscardMessages ()};
4834
4841
if (const Symbol *symbol{scope.FindSymbol (oprName)}) {
@@ -4842,8 +4849,8 @@ std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
4842
4849
for (std::size_t i{0 }; (!proc || isProcElemental) && i < actuals_.size ();
4843
4850
++i) {
4844
4851
const Symbol *generic{nullptr };
4845
- if (const Symbol *
4846
- binding{ FindBoundOp (oprName, i, generic, /* isSubroutine=*/ true )}) {
4852
+ if (const Symbol *binding{ FindBoundOp (oprName, i, generic,
4853
+ /* isSubroutine=*/ true , /* isAmbiguous= */ &isAmbiguous )}) {
4847
4854
// ignore inaccessible type-bound ASSIGNMENT(=) generic
4848
4855
if (!CheckAccessibleSymbol (scope, DEREF (generic))) {
4849
4856
const Symbol *resolution{GetBindingResolution (GetType (i), *binding)};
@@ -4967,7 +4974,8 @@ bool ArgumentAnalyzer::AreConformable() const {
4967
4974
4968
4975
// Look for a type-bound operator in the type of arg number passIndex.
4969
4976
const Symbol *ArgumentAnalyzer::FindBoundOp (parser::CharBlock oprName,
4970
- int passIndex, const Symbol *&generic, bool isSubroutine) {
4977
+ int passIndex, const Symbol *&generic, bool isSubroutine,
4978
+ bool *isAmbiguous) {
4971
4979
const auto *type{GetDerivedTypeSpec (GetType (passIndex))};
4972
4980
const semantics::Scope *scope{type ? type->scope () : nullptr };
4973
4981
if (scope) {
@@ -4989,6 +4997,9 @@ const Symbol *ArgumentAnalyzer::FindBoundOp(parser::CharBlock oprName,
4989
4997
// Use the most recent override of the binding, if any
4990
4998
return scope->FindComponent (binding->name ());
4991
4999
} else {
5000
+ if (isAmbiguous) {
5001
+ *isAmbiguous = pair.second ;
5002
+ }
4992
5003
context_.EmitGenericResolutionError (*generic, pair.second , isSubroutine);
4993
5004
}
4994
5005
}
@@ -5072,40 +5083,37 @@ void ArgumentAnalyzer::ConvertBOZAssignmentRHS(const DynamicType &lhsType) {
5072
5083
}
5073
5084
5074
5085
// Report error resolving opr when there is a user-defined one available
5075
- void ArgumentAnalyzer::SayNoMatch (const std::string &opr, bool isAssignment) {
5086
+ void ArgumentAnalyzer::SayNoMatch (
5087
+ const std::string &opr, bool isAssignment, bool isAmbiguous) {
5076
5088
std::string type0{TypeAsFortran (0 )};
5077
5089
auto rank0{actuals_[0 ]->Rank ()};
5090
+ std::string prefix{" No intrinsic or user-defined " s + opr + " matches" };
5091
+ if (isAmbiguous) {
5092
+ prefix = " Multiple specific procedures for the generic " s + opr + " match" ;
5093
+ }
5078
5094
if (actuals_.size () == 1 ) {
5079
5095
if (rank0 > 0 ) {
5080
- context_.Say (" No intrinsic or user-defined %s matches "
5081
- " rank %d array of %s" _err_en_US,
5082
- opr, rank0, type0);
5096
+ context_.Say (" %s rank %d array of %s" _err_en_US, prefix, rank0, type0);
5083
5097
} else {
5084
- context_.Say (" No intrinsic or user-defined %s matches "
5085
- " operand type %s" _err_en_US,
5086
- opr, type0);
5098
+ context_.Say (" %s operand type %s" _err_en_US, prefix, type0);
5087
5099
}
5088
5100
} else {
5089
5101
std::string type1{TypeAsFortran (1 )};
5090
5102
auto rank1{actuals_[1 ]->Rank ()};
5091
5103
if (rank0 > 0 && rank1 > 0 && rank0 != rank1) {
5092
- context_.Say (" No intrinsic or user-defined %s matches "
5093
- " rank %d array of %s and rank %d array of %s" _err_en_US,
5094
- opr, rank0, type0, rank1, type1);
5104
+ context_.Say (" %s rank %d array of %s and rank %d array of %s" _err_en_US,
5105
+ prefix, rank0, type0, rank1, type1);
5095
5106
} else if (isAssignment && rank0 != rank1) {
5096
5107
if (rank0 == 0 ) {
5097
- context_.Say (" No intrinsic or user-defined %s matches "
5098
- " scalar %s and rank %d array of %s" _err_en_US,
5099
- opr, type0, rank1, type1);
5108
+ context_.Say (" %s scalar %s and rank %d array of %s" _err_en_US, prefix,
5109
+ type0, rank1, type1);
5100
5110
} else {
5101
- context_.Say (" No intrinsic or user-defined %s matches "
5102
- " rank %d array of %s and scalar %s" _err_en_US,
5103
- opr, rank0, type0, type1);
5111
+ context_.Say (" %s rank %d array of %s and scalar %s" _err_en_US, prefix,
5112
+ rank0, type0, type1);
5104
5113
}
5105
5114
} else {
5106
- context_.Say (" No intrinsic or user-defined %s matches "
5107
- " operand types %s and %s" _err_en_US,
5108
- opr, type0, type1);
5115
+ context_.Say (
5116
+ " %s operand types %s and %s" _err_en_US, prefix, type0, type1);
5109
5117
}
5110
5118
}
5111
5119
}
0 commit comments