diff --git a/Cython/Compiler/Builtin.py b/Cython/Compiler/Builtin.py
index c39258dca3727eb24b6775b9b883c448b1d3f9ac..8d87af992d2013d83be6b4be52f93782864c7015 100644
--- a/Cython/Compiler/Builtin.py
+++ b/Cython/Compiler/Builtin.py
@@ -414,7 +414,7 @@ def init_builtins():
     init_builtin_types()
     init_builtin_structs()
     global list_type, tuple_type, dict_type, set_type, type_type
-    global bytes_type, str_type, unicode_type
+    global bytes_type, str_type, unicode_type, float_type
     type_type  = builtin_scope.lookup('type').type
     list_type  = builtin_scope.lookup('list').type
     tuple_type = builtin_scope.lookup('tuple').type
@@ -423,5 +423,6 @@ def init_builtins():
     bytes_type = builtin_scope.lookup('bytes').type
     str_type   = builtin_scope.lookup('str').type
     unicode_type = builtin_scope.lookup('unicode').type
+    float_type = builtin_scope.lookup('float').type
 
 init_builtins()
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index ce9f383c51019d0c408379a10d9414cf79651e2f..75bf4e624a74c3ad038729c1fe8f3fd532838b9d 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -2412,7 +2412,9 @@ class SimpleCallNode(CallNode):
                 if result_type.is_extension_type:
                     return result_type
                 elif result_type.is_builtin_type:
-                    if function.entry.name in Builtin.types_that_construct_their_instance:
+                    if function.entry.name == 'float':
+                        return PyrexTypes.c_double_type
+                    elif function.entry.name in Builtin.types_that_construct_their_instance:
                         return result_type
         return py_object_type
 
@@ -2447,7 +2449,17 @@ class SimpleCallNode(CallNode):
             self.arg_tuple = TupleNode(self.pos, args = self.args)
             self.arg_tuple.analyse_types(env)
             self.args = None
-            if function.is_name and function.type_entry:
+            if func_type is Builtin.type_type and function.entry.is_builtin and \
+                   function.entry.name in Builtin.types_that_construct_their_instance:
+                # calling a builtin type that returns a specific object type
+                if function.entry.name == 'float':
+                    # the following will come true later on in a transform
+                    self.type = PyrexTypes.c_double_type
+                    self.result_ctype = PyrexTypes.c_double_type
+                else:
+                    self.type = Builtin.builtin_types[function.entry.name]
+                    self.result_ctype = py_object_type
+            elif function.is_name and function.type_entry:
                 # We are calling an extension type constructor.  As
                 # long as we do not support __new__(), the result type
                 # is clear
diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py
index 35ac35f72c2ac5135a2f66e70e9be6f8994cfd25..b319a4d815f45fc6e753133e1c5d601a312e5927 100644
--- a/Cython/Compiler/PyrexTypes.py
+++ b/Cython/Compiler/PyrexTypes.py
@@ -2031,6 +2031,10 @@ def spanning_type(type1, type2):
         return type1
     elif type1.is_numeric and type2.is_numeric:
         return widest_numeric_type(type1, type2)
+    elif type1.is_builtin_type and type1.name == 'float' and type2.is_numeric:
+        return widest_numeric_type(c_double_type, type2)
+    elif type2.is_builtin_type and type2.name == 'float' and type1.is_numeric:
+        return widest_numeric_type(type1, c_double_type)
     elif type1.is_pyobject ^ type2.is_pyobject:
         return py_object_type
     elif type1.assignable_from(type2):
diff --git a/Cython/Compiler/TypeInference.py b/Cython/Compiler/TypeInference.py
index c142453667de70e92da8ae7848e7be2d77d6d3fa..d9b2ad916a84e124529e6b27abdb0fc11acd1ad8 100644
--- a/Cython/Compiler/TypeInference.py
+++ b/Cython/Compiler/TypeInference.py
@@ -191,16 +191,20 @@ class SimpleAssignmentTypeInferer:
             entry.type = py_object_type
 
 def find_safe_type(result_type, which_types_to_infer):
+    if which_types_to_infer == 'none':
+        return py_object_type
+
+    if result_type in (PyrexTypes.c_double_type, PyrexTypes.c_float_type, Builtin.float_type):
+        # Python's float type is just a C double, so it's safe to
+        # use the C type instead
+        return PyrexTypes.c_double_type
+
     if which_types_to_infer == 'all':
         return result_type
     elif which_types_to_infer == 'safe':
         if result_type.is_pyobject:
             # any specific Python type is always safe to infer
             return result_type
-        elif result_type in (PyrexTypes.c_double_type, PyrexTypes.c_float_type):
-            # Python's float type is just a C double, so it's safe to
-            # use the C type instead
-            return PyrexTypes.c_double_type
         elif result_type is PyrexTypes.c_bint_type:
             # 'bint' should behave exactly like Python's bool type ...
             return PyrexTypes.c_bint_type
diff --git a/tests/run/int_float_builtins_as_casts_T400.pyx b/tests/run/int_float_builtins_as_casts_T400.pyx
index c0fc52eaca90644f33f3f5496eded41b5f1146bd..fd2a7408d7262c32b26d96fd11fc926dec5ffec6 100644
--- a/tests/run/int_float_builtins_as_casts_T400.pyx
+++ b/tests/run/int_float_builtins_as_casts_T400.pyx
@@ -37,17 +37,17 @@ def int_to_pyssizet_int(int x):
     cdef Py_ssize_t r = int(x)
     return r
 
-@cython.test_assert_path_exists("//SingleAssignmentNode/CastNode")
-@cython.test_fail_if_path_exists("//SimpleCallNode")
-def double_to_pyssizet_float(double x):
-    """
-    >>> double_to_pyssizet_float(4.1)
-    4
-    >>> double_to_pyssizet_float(4)
-    4
-    """
-    cdef Py_ssize_t r = float(x)
-    return r
+## @cython.test_assert_path_exists("//SingleAssignmentNode/CastNode")
+## @cython.test_fail_if_path_exists("//SimpleCallNode")
+## def double_to_pyssizet_float(double x):
+##     """
+##     >>> double_to_pyssizet_float(4.1)
+##     4
+##     >>> double_to_pyssizet_float(4)
+##     4
+##     """
+##     cdef Py_ssize_t r = float(x)
+##     return r
 
 @cython.test_assert_path_exists("//SingleAssignmentNode/CastNode")
 @cython.test_fail_if_path_exists("//SimpleCallNode")
@@ -89,8 +89,7 @@ def short_to_double_int(short x):
     cdef double r = int(x)
     return r
 
-@cython.test_fail_if_path_exists("//SimpleCallNode",
-                                 "//SingleAssignmentNode/CastNode")
+@cython.test_fail_if_path_exists("//SimpleCallNode")
 def float_to_float_float(float x):
     """
     >>> 4.05 < float_to_float_float(4.1) < 4.15
diff --git a/tests/run/type_inference.pyx b/tests/run/type_inference.pyx
index 0666014b2be2fdff1c5250917f789df2c1ef6e3d..dd899fdf09ffb8b48e4c90b3d26285f61df2d225 100644
--- a/tests/run/type_inference.pyx
+++ b/tests/run/type_inference.pyx
@@ -149,6 +149,25 @@ def loop():
     assert typeof(a) == "long"
 
 
+@infer_types('safe')
+def double_inference():
+    """
+    >>> values, types = double_inference()
+    >>> values == (1.0, 1.0*2, 1.0*2.0+2.0*2.0, 1.0*2.0)
+    True
+    >>> types
+    ('double', 'double', 'double', 'Python object')
+    """
+    d_a = 1.0
+    d_b = d_a * float(2)
+    d_c = d_a * float(some_float_value()) + d_b * float(some_float_value())
+    o_d = d_a * some_float_value()
+    return (d_a,d_b,d_c,o_d), (typeof(d_a), typeof(d_b), typeof(d_c), typeof(o_d))
+
+cdef object some_float_value():
+    return 2.0
+
+
 @cython.test_fail_if_path_exists('//NameNode[@type.is_pyobject = True]')
 @cython.test_assert_path_exists('//InPlaceAssignmentNode/NameNode',
                                 '//NameNode[@type.is_pyobject]',