* 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/Objects/classobject.c b/Objects/classobject.c
index 40fe0c9..8164ced 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -417,13 +417,19 @@
 instance_concat(inst, other)
 	instanceobject *inst, *other;
 {
-	object *func, *res;
+	object *func, *arg, *res;
 
 	func = instance_getattr(inst, "__add__");
 	if (func == NULL)
 		return NULL;
-	res = call_object(func, (object *)other);
+	arg = mkvalue("(O)", other);
+	if (arg == NULL) {
+		DECREF(func);
+		return NULL;
+	}
+	res = call_object(func, arg);
 	DECREF(func);
+	DECREF(arg);
 	return res;
 }
 
@@ -568,12 +574,18 @@
 	object *other;
 	char *methodname;
 {
-	object *func, *res;
+	object *func, *arg, *res;
 
 	if ((func = instance_getattr(self, methodname)) == NULL)
 		return NULL;
-	res = call_object(func, other);
+	arg = mkvalue("O", other);
+	if (arg == NULL) {
+		DECREF(func);
+		return NULL;
+	}
+	res = call_object(func, arg);
 	DECREF(func);
+	DECREF(arg);
 	return res;
 }
 
@@ -653,6 +665,45 @@
 BINARY(instance_xor, "__xor__")
 BINARY(instance_or, "__or__")
 
+static int
+instance_coerce(pv, pw)
+	object **pv, **pw;
+{
+	object *v =  *pv;
+	object *w = *pw;
+	object *func;
+	object *res;
+	int outcome;
+
+	if (!is_instanceobject(v))
+		return 1; /* XXX shouldn't be possible */
+	func = instance_getattr((instanceobject *)v, "__coerce__");
+	if (func == NULL) {
+		err_clear();
+		return 1;
+	}
+	res = call_object(func, w);
+	if (res == NULL)
+		return -1;
+	if (res == None) {
+		DECREF(res);
+		return 1;
+	}
+	outcome = getargs(res, "(OO)", &v, &w);
+	if (!outcome || v->ob_type != w->ob_type ||
+			v->ob_type->tp_as_number == NULL) {
+		DECREF(res);
+		err_setstr(TypeError, "bad __coerce__ result");
+		return -1;
+	}
+	INCREF(v);
+	INCREF(w);
+	DECREF(res);
+	*pv = v;
+	*pw = w;
+	return 0;
+}
+
 static number_methods instance_as_number = {
 	instance_add,		/*nb_add*/
 	instance_sub,		/*nb_subtract*/
@@ -671,6 +722,7 @@
 	instance_and,		/*nb_and*/
 	instance_xor,		/*nb_xor*/
 	instance_or,		/*nb_or*/
+	instance_coerce,	/*nb_coerce*/
 };
 
 typeobject Instancetype = {
@@ -690,58 +742,6 @@
 	&instance_as_mapping,	/*tp_as_mapping*/
 };
 
-static int
-one_coerce(pv, pw)
-	object **pv, **pw;
-{
-	object *v = *pv;
-	object *w = *pw;
-	object *func;
-
-	if (!is_instanceobject(v))
-		return 1;
-	func = instance_getattr((instanceobject *)v, "__coerce__");
-	if (func == NULL) {
-		err_clear();
-		return 1;
-	}
-	if (func != NULL) {
-		object *res = call_object(func, w);
-		int outcome;
-		if (res == NULL)
-			return -1;
-		outcome = getargs(res, "(OO)", &v, &w);
-		if (!outcome || v->ob_type != w->ob_type ||
-			        v->ob_type->tp_as_number == NULL) {
-			DECREF(res);
-			err_setstr(TypeError, "bad __coerce__ result");
-			return -1;
-		}
-		INCREF(v);
-		INCREF(w);
-		DECREF(res);
-		*pv = v;
-		*pw = w;
-		return 0;
-	}
-}
-
-int
-instance_coerce(pv, pw)
-	object **pv, **pw;
-{
-	int outcome;
-	outcome = one_coerce(pv, pw);
-	if (outcome > 0) {
-		outcome = one_coerce(pw, pv);
-		if (outcome > 0) {
-			err_setstr(TypeError, "uncoerceable instance");
-			outcome = -1;
-		}
-	}
-	return outcome;
-}
-
 object *
 instance_convert(inst, methodname)
 	object *inst;
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index d154cab..5ce6202 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -299,6 +299,25 @@
 	return v->ob_fval != 0.0;
 }
 
+int
+float_coerce(pv, pw)
+	object **pv;
+	object **pw;
+{
+	if (is_intobject(*pw)) {
+		long x = getintvalue(*pw);
+		*pw = newfloatobject((double)x);
+		INCREF(*pv);
+		return 0;
+	}
+	else if (is_longobject(*pw)) {
+		*pw = newfloatobject(dgetlongvalue(*pw));
+		INCREF(*pv);
+		return 0;
+	}
+	return 1; /* Can't do it */
+}
+
 static number_methods float_as_number = {
 	float_add,	/*nb_add*/
 	float_sub,	/*nb_subtract*/
@@ -317,6 +336,7 @@
 	0,		/*nb_and*/
 	0,		/*nb_xor*/
 	0,		/*nb_or*/
+	float_coerce,	/*nb_coerce*/
 };
 
 typeobject Floattype = {
diff --git a/Objects/longobject.c b/Objects/longobject.c
index bf62c1f..f9e3765 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -1253,6 +1253,19 @@
 	return long_bitwise(a, '|', b);
 }
 
+int
+long_coerce(pv, pw)
+	object **pv;
+	object **pw;
+{
+	if (is_intobject(*pw)) {
+		*pw = newlongobject(getintvalue(*pw));
+		INCREF(*pv);
+		return 0;
+	}
+	return 1; /* Can't do it */
+}
+
 #define UF (object* (*) FPROTO((object *))) /* Unary function */
 #define BF (object* (*) FPROTO((object *, object *))) /* Binary function */
 #define IF (int (*) FPROTO((object *))) /* Int function */
@@ -1275,6 +1288,8 @@
 	BF long_and,	/*nb_and*/
 	BF long_xor,	/*nb_xor*/
 	BF long_or,	/*nb_or*/
+	(int (*) FPROTO((object **, object **)))
+	long_coerce,	/*nb_coerce*/
 };
 
 typeobject Longtype = {