src/class-finalize-impl.lisp: Check for duplicates with the right `:test'.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 10 Aug 2019 00:17:00 +0000 (01:17 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 10 Aug 2019 14:47:06 +0000 (15:47 +0100)
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.)

src/class-finalize-impl.lisp
test/bad.ref
test/bad.sod

index 58dc508..895b3c9 100644 (file)
 
     ;; 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)
                                                          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)
 
     ;; 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)
                                              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)))
index f5d0c6b..de3b354 100644 (file)
@@ -6,54 +6,62 @@
 * test/bad.sod:33:6: syntax error: Expected <identifier> 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 <identifier> 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 <identifier> 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 <identifier> 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 <identifier> 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
index 4ca273e..2799e0e 100644 (file)
@@ -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); }