@@ -178,7 +178,7 @@ class ArgumentAnalyzer {
178178 }
179179 // Find and return a user-defined assignment
180180 std::optional<ProcedureRef> TryDefinedAssignment ();
181- std::optional<ProcedureRef> GetDefinedAssignmentProc ();
181+ std::optional<ProcedureRef> GetDefinedAssignmentProc (bool &isAmbiguous );
182182 std::optional<DynamicType> GetType (std::size_t ) const ;
183183 void Dump (llvm::raw_ostream &);
184184
@@ -191,15 +191,16 @@ class ArgumentAnalyzer {
191191 MaybeExpr AnalyzeExprOrWholeAssumedSizeArray (const parser::Expr &);
192192 bool AreConformable () const ;
193193 const Symbol *FindBoundOp (parser::CharBlock, int passIndex,
194- const Symbol *&generic, bool isSubroutine);
194+ const Symbol *&generic, bool isSubroutine, bool *isAmbiguous = nullptr );
195195 void AddAssignmentConversion (
196196 const DynamicType &lhsType, const DynamicType &rhsType);
197197 bool OkLogicalIntegerAssignment (TypeCategory lhs, TypeCategory rhs);
198198 int GetRank (std::size_t ) const ;
199199 bool IsBOZLiteral (std::size_t i) const {
200200 return evaluate::IsBOZLiteral (GetExpr (i));
201201 }
202- void SayNoMatch (const std::string &, bool isAssignment = false );
202+ void SayNoMatch (
203+ const std::string &, bool isAssignment = false , bool isAmbiguous = false );
203204 std::string TypeAsFortran (std::size_t );
204205 bool AnyUntypedOrMissingOperand ();
205206
@@ -4781,7 +4782,9 @@ std::optional<ProcedureRef> ArgumentAnalyzer::TryDefinedAssignment() {
47814782 return std::nullopt ; // user-defined assignment not allowed for these args
47824783 }
47834784 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)}) {
47854788 if (context_.inWhereBody () && !procRef->proc ().IsElemental ()) { // C1032
47864789 context_.Say (
47874790 " Defined assignment in WHERE must be elemental, but '%s' is not" _err_en_US,
@@ -4791,9 +4794,11 @@ std::optional<ProcedureRef> ArgumentAnalyzer::TryDefinedAssignment() {
47914794 return std::move (*procRef);
47924795 }
47934796 if (isDefined == Tristate::Yes) {
4794- if (!lhsType || !rhsType || (lhsRank != rhsRank && rhsRank != 0 ) ||
4797+ if (isAmbiguous || !lhsType || !rhsType ||
4798+ (lhsRank != rhsRank && rhsRank != 0 ) ||
47954799 !OkLogicalIntegerAssignment (lhsType->category (), rhsType->category ())) {
4796- SayNoMatch (" ASSIGNMENT(=)" , true );
4800+ SayNoMatch (
4801+ " ASSIGNMENT(=)" , /* isAssignment=*/ true , /* isAmbiguous=*/ isAmbiguous);
47974802 }
47984803 } else if (!fatalErrors_) {
47994804 CheckAssignmentConformance ();
@@ -4822,13 +4827,15 @@ bool ArgumentAnalyzer::OkLogicalIntegerAssignment(
48224827 return true ;
48234828}
48244829
4825- std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc () {
4830+ std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc (
4831+ bool &isAmbiguous) {
48264832 const Symbol *proc{nullptr };
48274833 bool isProcElemental{false };
48284834 std::optional<int > passedObjectIndex;
48294835 std::string oprNameString{" assignment(=)" };
48304836 parser::CharBlock oprName{oprNameString};
48314837 const auto &scope{context_.context ().FindScope (source_)};
4838+ isAmbiguous = false ;
48324839 {
48334840 auto restorer{context_.GetContextualMessages ().DiscardMessages ()};
48344841 if (const Symbol *symbol{scope.FindSymbol (oprName)}) {
@@ -4842,8 +4849,8 @@ std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
48424849 for (std::size_t i{0 }; (!proc || isProcElemental) && i < actuals_.size ();
48434850 ++i) {
48444851 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 )}) {
48474854 // ignore inaccessible type-bound ASSIGNMENT(=) generic
48484855 if (!CheckAccessibleSymbol (scope, DEREF (generic))) {
48494856 const Symbol *resolution{GetBindingResolution (GetType (i), *binding)};
@@ -4967,7 +4974,8 @@ bool ArgumentAnalyzer::AreConformable() const {
49674974
49684975// Look for a type-bound operator in the type of arg number passIndex.
49694976const 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) {
49714979 const auto *type{GetDerivedTypeSpec (GetType (passIndex))};
49724980 const semantics::Scope *scope{type ? type->scope () : nullptr };
49734981 if (scope) {
@@ -4989,6 +4997,9 @@ const Symbol *ArgumentAnalyzer::FindBoundOp(parser::CharBlock oprName,
49894997 // Use the most recent override of the binding, if any
49904998 return scope->FindComponent (binding->name ());
49914999 } else {
5000+ if (isAmbiguous) {
5001+ *isAmbiguous = pair.second ;
5002+ }
49925003 context_.EmitGenericResolutionError (*generic, pair.second , isSubroutine);
49935004 }
49945005 }
@@ -5072,40 +5083,37 @@ void ArgumentAnalyzer::ConvertBOZAssignmentRHS(const DynamicType &lhsType) {
50725083}
50735084
50745085// 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) {
50765088 std::string type0{TypeAsFortran (0 )};
50775089 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+ }
50785094 if (actuals_.size () == 1 ) {
50795095 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);
50835097 } 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);
50875099 }
50885100 } else {
50895101 std::string type1{TypeAsFortran (1 )};
50905102 auto rank1{actuals_[1 ]->Rank ()};
50915103 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);
50955106 } else if (isAssignment && rank0 != rank1) {
50965107 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);
51005110 } 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);
51045113 }
51055114 } 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);
51095117 }
51105118 }
51115119}
0 commit comments