diff --git a/src/treeopt.in b/src/treeopt.in
index 6bdd54aae11559928e3a4dbd5ed8fdad98e4fba0..aac66cbaf214b1c674a19a35ed3138c3457e8fd3 100644
--- a/src/treeopt.in
+++ b/src/treeopt.in
@@ -1,6 +1,6 @@
 // -*- c -*-
 //
-// $Id: treeopt.in,v 1.41 2000/09/23 12:41:51 grubba Exp $
+// $Id: treeopt.in,v 1.42 2000/09/23 15:58:39 grubba Exp $
 //
 // The tree optimizer
 //
@@ -58,12 +58,32 @@ F_PUSH_ARRAY(0 = F_CONSTANT[$$->u.sval.type == T_ARRAY], *):
   ;
 
 // `+(`+(a,b),c)  =>  `+(a, b, c)
+// NOTE: We do some ugly stuff here to avoid
+//	 resolving the resulting type multiple times.
 F_APPLY(0 = F_CONSTANT
-	   [$$->u.sval.type == T_FUNCTION]
-	   [$$->u.sval.subtype == FUNCTION_BUILTIN]
-	   [$$->u.sval.u.efun->function == f_add],
-	   F_ARG_LIST(F_APPLY($0, 1), 2)):
-  F_APPLY($0, F_ARG_LIST($1, $2));
+	[$$->u.sval.type == T_FUNCTION]
+	[$$->u.sval.subtype == FUNCTION_BUILTIN]
+	[$$->u.sval.u.efun->function == f_add],
+	2 = F_ARG_LIST(3 = F_APPLY($0, 1), *)):
+  {
+    node *arglist = $2;
+    node *old_apply = $3;
+    ADD_NODE_REF2($1, _CAR(arglist) = $1);
+#ifdef SHARED_NODES
+    arglist->hash = hash_node(arglist);
+    arglist->node_info |= OPT_DEFROSTED;
+#endif /* SHARED_NODES */
+    free_node(old_apply);
+#ifdef PIKE_DEBUG
+    if (l_flag > 4) {
+      fprintf(stderr, "Result:    ");
+      print_tree(n);
+    }
+#endif /* PIKE_DEBUG */
+    n = arglist;
+    continue;
+  }
+  ;
 
 // Similar rule for `*() disabled, since the type for '*() isn't
 // correct for all cases.