Currently, when using an operator between two mismatched types or when the operator just isn't implemented, there is a lot output to wade through to obtain the callsite of the error. This is especially painful when using a remote session terminal and if you are using GNU screen as you need to scroll up to the top of the error message via the keyboard. For example...
writeln(1 == "1");
Output
error: unresolved call '==(1, "1")'
$CHPL_HOME/modules/internal/ChapelBase.chpl:116: note: candidates are: ==(a: bool, b: bool)
$CHPL_HOME/modules/internal/ChapelBase.chpl:122: note: ==(a: borrowed object, b: borrowed object)
$CHPL_HOME/modules/internal/ChapelBase.chpl:123: note: ==(a: enumerated, b: enumerated)
$CHPL_HOME/modules/internal/ChapelBase.chpl:127: note: ==(a: enumerated, b: enumerated)
$CHPL_HOME/modules/internal/ChapelBase.chpl:148: note: ==(param a: bool, param b: bool)
$CHPL_HOME/modules/internal/ChapelBase.chpl:152: note: ==(param a: enumerated, param b: enumerated)
$CHPL_HOME/modules/internal/ChapelBase.chpl:849: note: ==(a: _ddata, b: _ddata)
$CHPL_HOME/modules/internal/ChapelBase.chpl:852: note: ==(a: _ddata, b: _nilType)
$CHPL_HOME/modules/internal/ChapelBase.chpl:855: note: ==(a: _nilType, b: _ddata)
$CHPL_HOME/modules/internal/ChapelBase.chpl:1430: note: ==(a: c_void_ptr, b: c_void_ptr)
$CHPL_HOME/modules/internal/ChapelBase.chpl:1763: note: ==(a: uint(64), b: int(64))
$CHPL_HOME/modules/internal/ChapelBase.chpl:1773: note: ==(a: int(64), b: uint(64))
$CHPL_HOME/modules/internal/ChapelBase.chpl:1906: note: ==(a, b: a.type )
$CHPL_HOME/modules/internal/ChapelBase.chpl:1908: note: ==(a, b: _nilType)
$CHPL_HOME/modules/internal/ChapelBase.chpl:1910: note: ==(a: _nilType, b)
$CHPL_HOME/modules/internal/CPtr.chpl:228: note: ==(a: c_ptr, b: c_ptr)
$CHPL_HOME/modules/internal/CPtr.chpl:232: note: ==(a: c_ptr, b: c_void_ptr)
$CHPL_HOME/modules/internal/CPtr.chpl:236: note: ==(a: c_void_ptr, b: c_ptr)
$CHPL_HOME/modules/internal/CPtr.chpl:240: note: ==(a: c_ptr, b: _nilType)
$CHPL_HOME/modules/internal/CPtr.chpl:244: note: ==(a: _nilType, b: c_ptr)
$CHPL_HOME/modules/internal/CPtr.chpl:248: note: ==(a: c_void_ptr, b: _nilType)
$CHPL_HOME/modules/internal/CPtr.chpl:252: note: ==(a: _nilType, b: c_void_ptr)
$CHPL_HOME/modules/internal/CString.chpl:44: note: ==(s0: c_string, s1: c_string)
$CHPL_HOME/modules/internal/String.chpl:1747: note: ==(param s0: string, param s1: string)
$CHPL_HOME/modules/internal/String.chpl:1888: note: ==(a: string, b: string)
$CHPL_HOME/modules/internal/ChapelTuple.chpl:666: note: ==(a: _tuple, b: _tuple)
$CHPL_HOME/modules/internal/ChapelRange.chpl:631: note: ==(r1: range(?), r2: range(?))
$CHPL_HOME/modules/internal/ChapelRange.chpl:635: note: ==(r1: range(?), r2: range(?))
$CHPL_HOME/modules/internal/ChapelArray.chpl:1019: note: ==(d1: _distribution(?), d2: _distribution(?))
$CHPL_HOME/modules/internal/ChapelArray.chpl:2042: note: ==(d1: domain, d2: domain)
$CHPL_HOME/modules/internal/ChapelArray.chpl:2060: note: ==(d1: domain, d2: domain)
$CHPL_HOME/modules/internal/ChapelArray.chpl:2080: note: ==(d1: domain, d2: domain)
$CHPL_HOME/modules/internal/ChapelArray.chpl:2104: note: ==(d1: domain, d2: domain)
$CHPL_HOME/modules/internal/DefaultOpaque.chpl:47: note: ==(a: _OpaqueIndex, b: _nilType)
$CHPL_HOME/modules/internal/DefaultOpaque.chpl:50: note: ==(a: _nilType, b: _OpaqueIndex)
$CHPL_HOME/modules/internal/ChapelTaskID.chpl:29: note: ==(a: chpl_taskID_t, b: chpl_taskID_t)
$CHPL_HOME/modules/standard/SysBasic.chpl:119: note: ==(a: syserr, b: syserr)
$CHPL_HOME/modules/standard/SysBasic.chpl:121: note: ==(a: syserr, b: int(32))
$CHPL_HOME/modules/standard/SysBasic.chpl:123: note: ==(a: syserr, b: int(64))
$CHPL_HOME/modules/standard/SysBasic.chpl:125: note: ==(a: int(32), b: syserr)
$CHPL_HOME/modules/standard/SysBasic.chpl:127: note: ==(a: int(64), b: syserr)
$CHPL_HOME/modules/internal/ChapelBase.chpl:117: note: ==(a: int(8), b: int(8))
$CHPL_HOME/modules/internal/ChapelBase.chpl:117: note: ==(a: int(16), b: int(16))
$CHPL_HOME/modules/internal/ChapelBase.chpl:117: note: ==(a: int(32), b: int(32))
$CHPL_HOME/modules/internal/ChapelBase.chpl:117: note: ==(a: int(64), b: int(64))
$CHPL_HOME/modules/internal/ChapelBase.chpl:118: note: ==(a: uint(8), b: uint(8))
$CHPL_HOME/modules/internal/ChapelBase.chpl:118: note: ==(a: uint(16), b: uint(16))
$CHPL_HOME/modules/internal/ChapelBase.chpl:118: note: ==(a: uint(32), b: uint(32))
$CHPL_HOME/modules/internal/ChapelBase.chpl:118: note: ==(a: uint(64), b: uint(64))
$CHPL_HOME/modules/internal/ChapelBase.chpl:119: note: ==(a: real(32), b: real(32))
$CHPL_HOME/modules/internal/ChapelBase.chpl:119: note: ==(a: real(64), b: real(64))
$CHPL_HOME/modules/internal/ChapelBase.chpl:120: note: ==(a: imag(32), b: imag(32))
$CHPL_HOME/modules/internal/ChapelBase.chpl:120: note: ==(a: imag(64), b: imag(64))
$CHPL_HOME/modules/internal/ChapelBase.chpl:121: note: ==(a: complex(64), b: complex(64))
$CHPL_HOME/modules/internal/ChapelBase.chpl:121: note: ==(a: complex(128), b: complex(128))
$CHPL_HOME/modules/internal/ChapelBase.chpl:149: note: ==(param a, param b)
$CHPL_HOME/modules/internal/ChapelBase.chpl:149: note: ==(param a, param b)
$CHPL_HOME/modules/internal/ChapelBase.chpl:149: note: ==(param a, param b)
$CHPL_HOME/modules/internal/ChapelBase.chpl:149: note: ==(param a, param b)
$CHPL_HOME/modules/internal/ChapelBase.chpl:150: note: ==(param a, param b)
$CHPL_HOME/modules/internal/ChapelBase.chpl:150: note: ==(param a, param b)
$CHPL_HOME/modules/internal/ChapelBase.chpl:150: note: ==(param a, param b)
$CHPL_HOME/modules/internal/ChapelBase.chpl:150: note: ==(param a, param b)
$CHPL_HOME/modules/internal/String.chpl:182: note: ==(_arg1: chpl__inPlaceBuffer, _arg2: chpl__inPlaceBuffer)
$CHPL_HOME/modules/internal/String.chpl:206: note: ==(_arg1: __serializeHelper, _arg2: __serializeHelper)
$CHPL_HOME/modules/internal/String.chpl:231: note: ==(_arg1: codePointIndex, _arg2: codePointIndex)
$CHPL_HOME/modules/internal/OwnedObject.chpl:186: note: ==(_arg1: _owned, _arg2: _owned)
$CHPL_HOME/modules/internal/SharedObject.chpl:138: note: ==(_arg1: _shared, _arg2: _shared)
$CHPL_HOME/modules/internal/Atomics.chpl:176: note: ==(_arg1: AtomicBool, _arg2: AtomicBool)
$CHPL_HOME/modules/internal/Atomics.chpl:314: note: ==(_arg1: AtomicT, _arg2: AtomicT)
$CHPL_HOME/modules/internal/NetworkAtomics.chpl:32: note: ==(_arg1: RAtomicBool, _arg2: RAtomicBool)
$CHPL_HOME/modules/internal/NetworkAtomics.chpl:117: note: ==(_arg1: RAtomicT, _arg2: RAtomicT)
$CHPL_HOME/modules/internal/AtomicsCommon.chpl:23: note: ==(_arg1: atomic_refcnt, _arg2: atomic_refcnt)
$CHPL_HOME/modules/internal/ChapelSyncvar.chpl:108: note: ==(_arg1: _syncvar, _arg2: _syncvar)
$CHPL_HOME/modules/internal/ChapelSyncvar.chpl:633: note: ==(_arg1: _singlevar, _arg2: _singlevar)
$CHPL_HOME/modules/internal/ChapelSyncvar.chpl:886: note: ==(_arg1: chpl_sync_aux_t, _arg2: chpl_sync_aux_t)
$CHPL_HOME/modules/internal/ChapelSyncvar.chpl:912: note: ==(_arg1: chpl_single_aux_t, _arg2: chpl_single_aux_t)
$CHPL_HOME/modules/internal/ChapelLocale.chpl:485: note: ==(_arg1: localesBarrier, _arg2: localesBarrier)
$CHPL_HOME/modules/internal/DefaultRectangular.chpl:700: note: ==(_arg1: _remoteAccessData, _arg2: _remoteAccessData)
$CHPL_HOME/modules/internal/ChapelArray.chpl:898: note: ==(_arg1: dmap, _arg2: dmap)
$CHPL_HOME/modules/internal/ChapelArray.chpl:1040: note: ==(_arg1: _serialized_domain, _arg2: _serialized_domain)
$CHPL_HOME/modules/internal/ChapelArray.chpl:3986: note: ==(_arg1: _OpaqueIndex, _arg2: _OpaqueIndex)
$CHPL_HOME/modules/internal/LocaleTree.chpl:29: note: ==(_arg1: chpl_localeTreeRecord, _arg2: chpl_localeTreeRecord)
$CHPL_HOME/modules/internal/DefaultAssociative.chpl:36: note: ==(_arg1: chpl_TableEntry, _arg2: chpl_TableEntry)
$CHPL_HOME/modules/internal/ExternalArray.chpl:28: note: ==(_arg1: chpl_external_array, _arg2: chpl_external_array)
$CHPL_HOME/modules/internal/ChapelError.chpl:106: note: ==(_arg1: chpl_TaskErrors, _arg2: chpl_TaskErrors)
$CHPL_HOME/modules/internal/LocaleModelHelpSetup.chpl:44: note: ==(_arg1: chpl_root_locale_accum, _arg2: chpl_root_locale_accum)
$CHPL_HOME/modules/internal/LocaleModelHelpRuntime.chpl:38: note: ==(_arg1: chpl_localeID_t, _arg2: chpl_localeID_t)
$CHPL_HOME/modules/internal/LocaleModelHelpRuntime.chpl:45: note: ==(_arg1: chpl_comm_on_bundle_t, _arg2: chpl_comm_on_bundle_t)
$CHPL_HOME/modules/internal/LocaleModelHelpRuntime.chpl:48: note: ==(_arg1: chpl_task_bundle_t, _arg2: chpl_task_bundle_t)
$CHPL_HOME/modules/standard/CommDiagnostics.chpl:176: note: ==(_arg1: chpl_commDiagnostics, _arg2: chpl_commDiagnostics)
$CHPL_HOME/modules/standard/List.chpl:53: note: ==(_arg1: list, _arg2: list)
$CHPL_HOME/modules/standard/IO.chpl:750: note: ==(_arg1: iostyle, _arg2: iostyle)
$CHPL_HOME/modules/standard/IO.chpl:1061: note: ==(_arg1: qio_conv_t, _arg2: qio_conv_t)
$CHPL_HOME/modules/standard/IO.chpl:1256: note: ==(_arg1: file, _arg2: file)
$CHPL_HOME/modules/standard/IO.chpl:1905: note: ==(_arg1: channel, _arg2: channel)
$CHPL_HOME/modules/standard/IO.chpl:2026: note: ==(_arg1: ioChar, _arg2: ioChar)
$CHPL_HOME/modules/standard/IO.chpl:2058: note: ==(_arg1: ioNewline, _arg2: ioNewline)
$CHPL_HOME/modules/standard/IO.chpl:2088: note: ==(_arg1: ioLiteral, _arg2: ioLiteral)
$CHPL_HOME/modules/standard/IO.chpl:2112: note: ==(_arg1: ioBits, _arg2: ioBits)
$CHPL_HOME/modules/standard/IO.chpl:4398: note: ==(_arg1: ItemReader, _arg2: ItemReader)
$CHPL_HOME/modules/standard/IO.chpl:4440: note: ==(_arg1: ItemWriter, _arg2: ItemWriter)
$CHPL_HOME/modules/standard/Sys.chpl:215: note: ==(_arg1: sys_sockaddr_t, _arg2: sys_sockaddr_t)
$CHPL_HOME/modules/standard/Sys.chpl:224: note: ==(_arg1: sys_addrinfo_t, _arg2: sys_addrinfo_t)
$CHPL_HOME/modules/standard/Regexp.chpl:344: note: ==(_arg1: qio_regexp_options_t, _arg2: qio_regexp_options_t)
$CHPL_HOME/modules/standard/Regexp.chpl:384: note: ==(_arg1: qio_regexp_string_piece_t, _arg2: qio_regexp_string_piece_t)
$CHPL_HOME/modules/standard/Regexp.chpl:506: note: ==(_arg1: stringPart, _arg2: stringPart)
$CHPL_HOME/modules/standard/Regexp.chpl:527: note: ==(_arg1: reMatch, _arg2: reMatch)
$CHPL_HOME/modules/standard/Regexp.chpl:573: note: ==(_arg1: regexp, _arg2: regexp)
One possible easy enhancement would be to show the callsite of the offending expression at the end of the message as well as at the beginning. Another, and in my opinion the ideal, would be to only show operators for the types uses. Like for example, for writeln(1 == "1") could show...
error: unresolved call '==(1, "1")'
$CHPL_HOME/modules/internal/ChapelBase.chpl:117: note: candidates are: ==(a: int(64), b: int(64))
$CHPL_HOME/modules/internal/String.chpl:1888: note: ==(a: string, b: string)
That would be more than enough, I believe.
I agree (I think we all do) that it'd be nice to clean this up. One issue with only showing candidates where one of the types matches is that both arguments may coerce to a third type which is the right / expected match. That said, it still seems like we could eliminate a lot of the candidates.
A completely different approach than trying to be smart about matches would be to say something like "candidates are...", and then to print just a few (could be an arbitrary first few for now, a smart first few later), along with a message saying "...67 other candidates elided. Use --list-all-candidates to see them."
Definitely in favor of the --list-all-candidates option!
We've also in the past talked about making operator overloads (optionally?) be methods. That could help if our candidate list output for methods continues to only include methods on the receiver type. The trouble with this is that it might require multi-method virtual dispatch, for example if I had class Number { } and class Integer : Number { } and + was implemented on both of these (as methods), we wouldn't want to single-dispatch + since both arguments probably need to be the same for + to make sense. In C++ the answer to this issue is that methods don't have to allow virtual dispatch.
Anyway at the moment I'd be more in favor of finding a way to reduce the candidate list. One thing we could consider for operators specifically is to pre-filter the list similarly to how we pre-filter methods - we choose the 1st argument (arbitrarily) and look for functions that could match that argument, and then produce errors listing only those.
I think this issue can be closed, the output today is:
foo.chpl:1: error: unresolved call '==(1, "1")'
$CHPL_HOME/modules/internal/ChapelBase.chpl:132: note: this candidate did not match: ==(a: bool, b: bool)
foo.chpl:1: note: because call actual argument #1 with type int(64)
$CHPL_HOME/modules/internal/ChapelBase.chpl:132: note: is passed to formal 'a: bool'
$CHPL_HOME/modules/internal/ChapelBase.chpl:165: note: candidates are: ==(param a: bool, param b: bool)
$CHPL_HOME/modules/internal/ChapelBase.chpl:136: note: ==(a: imag(32), b: imag(32))
note: and 104 other candidates, use --print-all-candidates to see them
I'd tend to agree with that if @LouisJenkinsCS does.
Feel free to close this issue, I'm satisfied.
-------- Original message --------
From: Brad Chamberlain notifications@github.com
Date: 2/21/20 12:26 PM (GMT-05:00)
To: chapel-lang/chapel chapel@noreply.github.com
Cc: Louis Jenkins louisjenkinscs@hotmail.com, Mention mention@noreply.github.com
Subject: Re: [chapel-lang/chapel] Improve error messages for unresolved operators (#11611)
I'd tend to agree with that if @LouisJenkinsCShttps://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FLouisJenkinsCS&data=02%7C01%7C%7C2010a8a6310f4d8cb23008d7b6f33104%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637179027919222597&sdata=lmUcd1hhMJPCzB%2B7qzcAnf4CdlLA3gqf9x5McHVV8vI%3D&reserved=0 does.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fchapel-lang%2Fchapel%2Fissues%2F11611%3Femail_source%3Dnotifications%26email_token%3DABASPJRLM4B7CLI5KCAPVQLREAFENA5CNFSM4GDBCMSKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEMTOQCA%23issuecomment-589752328&data=02%7C01%7C%7C2010a8a6310f4d8cb23008d7b6f33104%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637179027919222597&sdata=%2FPRsVRiSGMtuFIfrImoNOTvY0hh81zaWIHHlu8NphsI%3D&reserved=0, or unsubscribehttps://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FABASPJVAD4IEZDLCB6TCKZDREAFENANCNFSM4GDBCMSA&data=02%7C01%7C%7C2010a8a6310f4d8cb23008d7b6f33104%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637179027919232591&sdata=vNUJCMv4qiK43AXWknCBP3n2Kd6DXev0QqS8y%2BCzFKo%3D&reserved=0.
Most helpful comment
I agree (I think we all do) that it'd be nice to clean this up. One issue with only showing candidates where one of the types matches is that both arguments may coerce to a third type which is the right / expected match. That said, it still seems like we could eliminate a lot of the candidates.
A completely different approach than trying to be smart about matches would be to say something like "candidates are...", and then to print just a few (could be an arbitrary first few for now, a smart first few later), along with a message saying "...67 other candidates elided. Use --list-all-candidates to see them."