From: Mark Wooding Date: Sat, 10 Aug 2019 00:17:00 +0000 (+0100) Subject: src/class-finalize-impl.lisp: Check for duplicates with the right `:test'. X-Git-Url: https://git.distorted.org.uk/~mdw/sod/commitdiff_plain/ed3ce6c2352d76442b79badfbe08bc6ecde6934d src/class-finalize-impl.lisp: Check for duplicates with the right `:test'. I noticed that Sod failed to diagnose a class containing duplicate slot names. Thinking that this was a stupid omission, I kludged a check into `make-sod-slot' (and a matching check into `make-sod-message'), thinking that it seemed rather difficult to provide a proper location of the existing definition. Then I tripped over this code, and wondered why it wasn't working. Of course, the problem was that it tries to compare strings using `eql'. Fix this. Use `equal' here rather than the more specific `string=' because (a) `find-duplicates' uses a hashtable if the :test function is suitable, and (b) it reports the duplicates in the right order in that codepath. (That the other codepaths don't work the same way is, of course, a bug which should be fixed.) --- diff --git a/src/class-finalize-impl.lisp b/src/class-finalize-impl.lisp index 58dc508..895b3c9 100644 --- a/src/class-finalize-impl.lisp +++ b/src/class-finalize-impl.lisp @@ -391,7 +391,9 @@ ;; Make sure direct slots have distinct names. (find-duplicates (simple-complain "slot name" #'sod-slot-name) - (sod-class-slots class) :key #'sod-slot-name) + (sod-class-slots class) + :key #'sod-slot-name + :test #'equal) ;; Make sure there's at most one initializer for each slot. (flet ((check-initializer-list (list kind) @@ -405,7 +407,8 @@ in class `~A'" kind slot class) (simple-previous previous))) - list :key #'sod-initializer-slot))) + list + :key #'sod-initializer-slot))) (check-initializer-list (sod-class-instance-initializers class) "instance") (check-initializer-list (sod-class-class-initializers class) @@ -413,7 +416,9 @@ ;; Make sure messages have distinct names. (find-duplicates (simple-complain "message name" #'sod-message-name) - (sod-class-messages class) :key #'sod-message-name) + (sod-class-messages class) + :key #'sod-message-name + :test #'equal) ;; Make sure methods are sufficiently distinct. (find-duplicates (lambda (method previous) @@ -426,7 +431,8 @@ class) (simple-previous previous)) (sod-class-methods class) - :key #'sod-method-function-name :test #'equal) + :key #'sod-method-function-name + :test #'equal) ;; Make sure superclasses have distinct nicknames. (let ((state (make-inheritance-path-reporter-state class))) diff --git a/test/bad.ref b/test/bad.ref index f5d0c6b..de3b354 100644 --- a/test/bad.ref +++ b/test/bad.ref @@ -6,54 +6,62 @@ * test/bad.sod:33:6: syntax error: Expected but found `{' * test/bad.sod:33:6: syntax error: Expected `:' but found `{' * test/bad.sod:36:12: syntax error: Expected `:' but found `{' -* test/bad.sod:43:17: error: Slot declarations cannot have function type -* test/bad.sod:43:19: syntax error: Expected but found `.' -* test/bad.sod:45:2: error: No message in class `Wrong' with name `fizzbuzz' -* test/bad.sod:45:12: error: No superclass of `Wrong' with nickname `wtf' -* test/bad.sod:45:26: error: No instance slot in class `Wrong' with name `z' -* test/bad.sod:45:30: syntax error: Expected but found `=' -* test/bad.sod:45:33: error: No superclass of `Wrong' with nickname `x' -* test/bad.sod:46:29: syntax error: Expected `;' but found `{' -* test/bad.sod:46:29: syntax error: Expected `}' but found `{' +* test/bad.sod:45:12: error: Slot declarations cannot have function type +* test/bad.sod:45:14: syntax error: Expected but found `.' +* test/bad.sod:47:2: error: No message in class `Wrong' with name `fizzbuzz' +* test/bad.sod:47:12: error: No superclass of `Wrong' with nickname `wtf' +* test/bad.sod:47:26: error: No instance slot in class `Wrong' with name `z' +* test/bad.sod:47:30: syntax error: Expected but found `=' +* test/bad.sod:47:33: error: No superclass of `Wrong' with nickname `x' +* test/bad.sod:48:29: syntax error: Expected `;' but found `{' +* test/bad.sod:48:29: syntax error: Expected `}' but found `{' +* test/bad.sod:42:7: error: Duplicate slot name `x' in class `Wrong' +* test/bad.sod:40:11: note: Previous definition was here +* test/bad.sod:44:25: error: Duplicate slot name `x' in class `Wrong' +* test/bad.sod:40:11: note: Previous definition was here +* test/bad.sod:45:7: error: Duplicate slot name `x' in class `Wrong' +* test/bad.sod:40:11: note: Previous definition was here * test/bad.sod:41:13: error: Duplicate initializer for instance slot `int wrong.x' in class `Wrong' * test/bad.sod:40:11: note: Previous definition was here -* test/bad.sod:42:13: error: Duplicate initializer for instance slot `int wrong.x' in class `Wrong' +* test/bad.sod:43:13: error: Duplicate initializer for instance slot `int wrong.x' in class `Wrong' +* test/bad.sod:40:11: note: Previous definition was here +* test/bad.sod:44:25: error: Duplicate initializer for instance slot `int wrong.x' in class `Wrong' * test/bad.sod:40:11: note: Previous definition was here * test/bad.sod:40:2: error: Duplicate primary direct method for message `void wrong.frob(void)' in classs `Wrong' * test/bad.sod:38:2: note: Previous definition was here -* test/bad.sod:46:29: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `{' -* test/bad.sod:46:49: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `}' -* test/bad.sod:47:0: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `}' -* test/bad.sod:52:30: error: Type mismatch for keyword argument `x' in methods for message `void fail.badkw(?int x)' applicable to class `Arrgh' -* test/bad.sod:54:2: note: Type `double' declared in primary direct method of `Arrgh' (defined here) -* test/bad.sod:49:43: note: Type `int' declared in message definition in `Fail' (here) -* test/bad.sod:50:21: note: Class `Fail' is a direct superclass of `Unlikely', defined here -* test/bad.sod:52:30: note: Class `Unlikely' is a direct superclass of `Arrgh', defined here -* test/bad.sod:52:30: error: Type mismatch for keyword argument `y' in methods for message `void fail.badkw(?int x)' applicable to class `Arrgh' -* test/bad.sod:51:53: note: Type `int' declared in primary direct method of `Whoops' (defined here) -* test/bad.sod:52:30: note: Class `Whoops' is a direct superclass of `Arrgh', defined here -* test/bad.sod:50:58: note: Type `double' declared in primary direct method of `Unlikely' (defined here) -* test/bad.sod:60:41: error: Duplicate nickname `sub' in superclasses of `BadNicks': used by `RSub' and `LSub' -* test/bad.sod:60:41: note: Class `RSub' is a direct superclass of `BadNicks', defined here -* test/bad.sod:60:41: note: Class `LSub' is a direct superclass of `BadNicks', defined here -* test/bad.sod:60:41: error: Duplicate nickname `join' in superclasses of `BadNicks': used by `JSuper' and `BadNicks' -* test/bad.sod:58:32: note: Class `JSuper' is a direct superclass of `LSub', defined here -* test/bad.sod:66:37: error: Ill-formed superclass graph: can't construct class precedence list for `Splinch' -* test/bad.sod:66:37: note: Class `Splinch' orders `SodObject' before `Nioj' -* test/bad.sod:64:24: note: Class `Join' orders `Left' before `SodObject' -* test/bad.sod:66:37: note: Class `Join' is a direct superclass of `Splinch', defined here -* test/bad.sod:65:24: note: Class `Nioj' orders `Nioj' before `Left' and `SodObject' -* test/bad.sod:66:37: note: Class `Nioj' is a direct superclass of `Splinch', defined here -* test/bad.sod:67:37: error: Class `Wrong' is incomplete -* test/bad.sod:67:37: error: In `Hopeless', chain-to class `Super' is not a proper superclass -* test/bad.sod:83:46: error: No obvious choice for implicit metaclass: candidates are `MyClass' and `MyOtherClass' -* test/bad.sod:78:26: note: Direct superclass `MyObject' defined here has metaclass `MyClass' -* test/bad.sod:82:58: note: Direct superclass `MyOtherObject' defined here has metaclass `MyOtherClass' -* test/bad.sod:83:46: error: Metaclass `MyClass' of `WhichMetaClass' isn't a subclass of `MyOtherClass' -* test/bad.sod:82:58: note: Direct superclass `MyOtherObject' defined here has metaclass `MyOtherClass' -* test/bad.sod:88:0: error: Class `dismissed' is incomplete -* test/bad.sod:88:0: syntax error: Expected `{' but found `;' -* test/bad.sod:88:0: syntax error: Expected `}' but found `;' -* test/bad.sod:88:0: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `;' -* sod: Finished with 34 errors +* test/bad.sod:48:29: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `{' +* test/bad.sod:48:49: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `}' +* test/bad.sod:49:0: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `}' +* test/bad.sod:54:30: error: Type mismatch for keyword argument `x' in methods for message `void fail.badkw(?int x)' applicable to class `Arrgh' +* test/bad.sod:56:2: note: Type `double' declared in primary direct method of `Arrgh' (defined here) +* test/bad.sod:51:43: note: Type `int' declared in message definition in `Fail' (here) +* test/bad.sod:52:21: note: Class `Fail' is a direct superclass of `Unlikely', defined here +* test/bad.sod:54:30: note: Class `Unlikely' is a direct superclass of `Arrgh', defined here +* test/bad.sod:54:30: error: Type mismatch for keyword argument `y' in methods for message `void fail.badkw(?int x)' applicable to class `Arrgh' +* test/bad.sod:53:53: note: Type `int' declared in primary direct method of `Whoops' (defined here) +* test/bad.sod:54:30: note: Class `Whoops' is a direct superclass of `Arrgh', defined here +* test/bad.sod:52:58: note: Type `double' declared in primary direct method of `Unlikely' (defined here) +* test/bad.sod:62:41: error: Duplicate nickname `sub' in superclasses of `BadNicks': used by `RSub' and `LSub' +* test/bad.sod:62:41: note: Class `RSub' is a direct superclass of `BadNicks', defined here +* test/bad.sod:62:41: note: Class `LSub' is a direct superclass of `BadNicks', defined here +* test/bad.sod:62:41: error: Duplicate nickname `join' in superclasses of `BadNicks': used by `JSuper' and `BadNicks' +* test/bad.sod:60:32: note: Class `JSuper' is a direct superclass of `LSub', defined here +* test/bad.sod:68:37: error: Ill-formed superclass graph: can't construct class precedence list for `Splinch' +* test/bad.sod:68:37: note: Class `Splinch' orders `SodObject' before `Nioj' +* test/bad.sod:66:24: note: Class `Join' orders `Left' before `SodObject' +* test/bad.sod:68:37: note: Class `Join' is a direct superclass of `Splinch', defined here +* test/bad.sod:67:24: note: Class `Nioj' orders `Nioj' before `Left' and `SodObject' +* test/bad.sod:68:37: note: Class `Nioj' is a direct superclass of `Splinch', defined here +* test/bad.sod:69:37: error: Class `Wrong' is incomplete +* test/bad.sod:69:37: error: In `Hopeless', chain-to class `Super' is not a proper superclass +* test/bad.sod:85:46: error: No obvious choice for implicit metaclass: candidates are `MyClass' and `MyOtherClass' +* test/bad.sod:80:26: note: Direct superclass `MyObject' defined here has metaclass `MyClass' +* test/bad.sod:84:58: note: Direct superclass `MyOtherObject' defined here has metaclass `MyOtherClass' +* test/bad.sod:85:46: error: Metaclass `MyClass' of `WhichMetaClass' isn't a subclass of `MyOtherClass' +* test/bad.sod:84:58: note: Direct superclass `MyOtherObject' defined here has metaclass `MyOtherClass' +* test/bad.sod:90:0: error: Class `dismissed' is incomplete +* test/bad.sod:90:0: syntax error: Expected `{' but found `;' +* test/bad.sod:90:0: syntax error: Expected `}' but found `;' +* test/bad.sod:90:0: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `;' +* sod: Finished with 38 errors ; rc = 2 diff --git a/test/bad.sod b/test/bad.sod index 4ca273e..2799e0e 100644 --- a/test/bad.sod +++ b/test/bad.sod @@ -39,8 +39,10 @@ class Wrong { int x = 2; wrong.x = 7; + int x; wrong.x = 3; - int filler, y(), .z[45], q; + const char *x = "hello"; + int x, y(), .z[45], q; int wrong.fizzbuzz(int n) extern; wtf.y = 19, wrong.z = 69, x.= r; int (*bogon)(const char *) { return strlen(p); }