* classobject.[ch], {float,long,int}object.c, bltinmodule.c:
  coercion is now completely generic.
* ceval.c: for instances, don't coerce for + and *; * reverses
  arguments if left one is non-instance numeric and right one sequence.
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index cce19e1..86deac3 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -781,10 +781,7 @@
    Increment the reference count on each argument.
    Return -1 and raise an exception if no coercion is possible
    (and then no reference count is incremented).
-   XXX This should be distributed over the various numeric types,
-   XXX but for now I don't see how to implement that.
-   XXX So, for now, if you add a new numeric type,
-   XXX you must add to this function as well. */
+*/
 
 int
 coerce(pv, pw)
@@ -792,36 +789,23 @@
 {
 	register object *v = *pv;
 	register object *w = *pw;
+	int res;
+
 	if (v->ob_type == w->ob_type) {
 		INCREF(v);
 		INCREF(w);
 		return 0;
 	}
-	if (is_instanceobject(v) || is_instanceobject(w))
-		return instance_coerce(pv, pw);
-	if (v->ob_type->tp_as_number == NULL ||
-					w->ob_type->tp_as_number == NULL) {
-		err_setstr(TypeError, "mixing number and non-number");
-		return -1;
+	if (v->ob_type->tp_as_number && v->ob_type->tp_as_number->nb_coerce) {
+		res = (*v->ob_type->tp_as_number->nb_coerce)(pv, pw);
+		if (res <= 0)
+			return res;
 	}
-	if (is_floatobject(v) || is_floatobject(w)) {
-		v = builtin_float((object *)0, v);
-		w = builtin_float((object *)0, w);
+	if (w->ob_type->tp_as_number && w->ob_type->tp_as_number->nb_coerce) {
+		res = (*w->ob_type->tp_as_number->nb_coerce)(pw, pv);
+		if (res <= 0)
+			return res;
 	}
-	else if (is_longobject(v) || is_longobject(w)) {
-		v = builtin_long((object *)0, v);
-		w = builtin_long((object *)0, w);
-	}
-	else {
-		err_setstr(TypeError, "can't coerce numeric types?!?!?");
-		return -1;
-	}
-	if (v == NULL || w == NULL) {
-		XDECREF(v);
-		XDECREF(w);
-		return -1;
-	}
-	*pv = v;
-	*pw = w;
-	return 0;
+	err_setstr(TypeError, "number coercion failed");
+	return -1;
 }
diff --git a/Python/ceval.c b/Python/ceval.c
index ad679a6..5b72d8e 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1532,7 +1532,9 @@
 add(v, w)
 	object *v, *w;
 {
-	if (v->ob_type->tp_as_number != NULL) {
+	if (v->ob_type->tp_as_sequence != NULL)
+		return (*v->ob_type->tp_as_sequence->sq_concat)(v, w);
+	else if (v->ob_type->tp_as_number != NULL) {
 		object *x;
 		if (coerce(&v, &w) != 0)
 			return NULL;
@@ -1541,8 +1543,6 @@
 		DECREF(w);
 		return x;
 	}
-	else if (v->ob_type->tp_as_sequence != NULL)
-		return (*v->ob_type->tp_as_sequence->sq_concat)(v, w);
 	else {
 		err_setstr(TypeError, "+ not supported by operands");
 		return NULL;
@@ -1571,16 +1571,27 @@
 	object *v, *w;
 {
 	typeobject *tp;
-	if (is_intobject(v) && w->ob_type->tp_as_sequence != NULL) {
-		/* int*sequence -- swap v and w */
+	tp = v->ob_type;
+	if (tp->tp_as_number != NULL &&
+	    w->ob_type->tp_as_sequence != NULL &&
+	    !is_instanceobject(v)) {
+		/* number*sequence -- swap v and w */
 		object *tmp = v;
 		v = w;
 		w = tmp;
+		tp = v->ob_type;
 	}
-	tp = v->ob_type;
 	if (tp->tp_as_number != NULL) {
 		object *x;
-		if (coerce(&v, &w) != 0)
+		if (is_instanceobject(v)) {
+			/* Instances of user-defined classes get their
+			   other argument uncoerced, so they may
+			   implement sequence*number as well as
+			   number*number. */
+			INCREF(v);
+			INCREF(w);
+		}
+		else if (coerce(&v, &w) != 0)
 			return NULL;
 		x = (*v->ob_type->tp_as_number->nb_multiply)(v, w);
 		DECREF(v);