diff --git a/spec/compiler/lexer/lexer_spec.cr b/spec/compiler/lexer/lexer_spec.cr
index cc23045224c24655e701cecb7db246d7b77fea5f..af0851db0233057db96733692727b6aae5cc46d3 100755
--- a/spec/compiler/lexer/lexer_spec.cr
+++ b/spec/compiler/lexer/lexer_spec.cr
@@ -185,6 +185,8 @@ describe "Lexer" do
   it_lexes_i64 ["2147483648", "-2147483649", "-9223372036854775808"]
   it_lexes_u64 ["9223372036854775808", "-9223372036854775809"]
   it_lexes_u64 ["18446744073709551615", "18446744073709551615", "14146167139683460000"]
+  it_lexes_i64 [["0x3fffffffffffffff", "4611686018427387903"]]
+  it_lexes_u64 [["0xffffffffffffffff", "18446744073709551615"]]
 
   it_lexes_char "'a'", 'a'
   it_lexes_char "'\\b'", 8.chr
@@ -235,6 +237,10 @@ describe "Lexer" do
 
   assert_syntax_error "18446744073709551616", "18446744073709551616 doesn't fit in an UInt64"
 
+  assert_syntax_error "0xFF_i8", "255 doesn't fit in an Int8"
+  assert_syntax_error "0200_i8", "128 doesn't fit in an Int8"
+  assert_syntax_error "0b10000000_i8", "128 doesn't fit in an Int8"
+
   it "lexes not instance var" do
     lexer = Lexer.new "!@foo"
     token = lexer.next_token
@@ -362,6 +368,15 @@ describe "Lexer" do
     (token.value as Char).ord.should eq(0x10FFFF)
   end
 
+  it "lexes float then zero (bug)" do
+    lexer = Lexer.new "2.5 0"
+    lexer.next_token.number_kind.should eq(:f64)
+    lexer.next_token.type.should eq(:SPACE)
+    token = lexer.next_token
+    token.type.should eq(:NUMBER)
+    token.number_kind.should eq(:i32)
+  end
+
   assert_syntax_error "'\\uFEDZ'", "expected hexadecimal character in unicode escape"
   assert_syntax_error "'\\u{}'", "expected hexadecimal character in unicode escape"
   assert_syntax_error "'\\u{110000}'", "invalid unicode codepoint (too large)"
diff --git a/src/compiler/crystal/syntax/lexer.cr b/src/compiler/crystal/syntax/lexer.cr
index 7ac78b3d513bd4499e23bb8d772578d66da4af31..d5344471f96072ae49cde7054a21ad77222deeac 100644
--- a/src/compiler/crystal/syntax/lexer.cr
+++ b/src/compiler/crystal/syntax/lexer.cr
@@ -191,7 +191,7 @@ module Crystal
         when '>'
           next_char :"->"
         when '0'
-          scan_zero_number start, multiplier: -1, negative: true
+          scan_zero_number start, negative: true
         when '1', '2', '3', '4', '5', '6', '7', '8', '9'
           scan_number start, negative: true
         else
@@ -1153,36 +1153,12 @@ module Crystal
       raise "#{string_value} doesn't fit in an UInt64", @token, (current_pos - start)
     end
 
-    def scan_hex_number(multiplier = 1)
-      @token.type = :NUMBER
-      num = 0
-      next_char
-
-      while true
-        char = next_char
-        if char == '_'
-        else
-          hex_value = char_to_hex(char) { nil }
-          if hex_value
-            num = 16 * num + hex_value
-          else
-            break
-          end
-        end
-      end
-
-      num *= multiplier
-      @token.value = num.to_s
-
-      consume_optional_int_suffix
-    end
-
-    def scan_zero_number(start, multiplier = 1, negative = false)
+    def scan_zero_number(start, negative = false)
       case peek_next_char
       when 'x'
-        scan_hex_number(multiplier)
+        scan_hex_number(start, negative)
       when 'b'
-        scan_bin_number(multiplier)
+        scan_bin_number(start, negative)
       when '.'
         scan_number(start)
       when 'i'
@@ -1221,13 +1197,32 @@ module Crystal
           scan_number(start)
         end
       else
-        scan_octal_number(multiplier)
+        scan_octal_number(start, negative)
       end
     end
 
-    def scan_octal_number(multiplier = 1)
-      @token.type = :NUMBER
-      num = 0
+    def scan_bin_number(start, negative)
+      next_char
+
+      num = 0_u64
+      while true
+        case next_char
+        when '0'
+          num *= 2
+        when '1'
+          num = num * 2 + 1
+        when '_'
+          # Nothing
+        else
+          break
+        end
+      end
+
+      finish_scan_prefixed_number num, negative, start
+    end
+
+    def scan_octal_number(start, negative)
+      num = 0_u64
 
       while true
         char = next_char
@@ -1239,45 +1234,53 @@ module Crystal
         end
       end
 
-      num *= multiplier
-      @token.value = num.to_s
-
-      consume_optional_int_suffix
+      finish_scan_prefixed_number num, negative, start
     end
 
-    def scan_bin_number(multiplier = 1)
-      @token.type = :NUMBER
-      num = 0
+    def scan_hex_number(start, negative = false)
       next_char
 
+      num = 0_u64
       while true
-        case next_char
-        when '0'
-          num *= 2
-        when '1'
-          num = num * 2 + 1
-        when '_'
-          # Nothing
+        char = next_char
+        if char == '_'
         else
-          break
+          hex_value = char_to_hex(char) { nil }
+          if hex_value
+            num = num * 16 + hex_value
+          else
+            break
+          end
         end
       end
 
-      num *= multiplier
-      @token.value = num.to_s
-
-      consume_optional_int_suffix
+      finish_scan_prefixed_number num, negative, start
     end
 
-    def consume_optional_int_suffix
+    def finish_scan_prefixed_number(num, negative, start)
+      if negative
+        string_value = (-1 * num.to_i64).to_s
+      else
+        string_value = num.to_s
+      end
+
+      name_length = string_value.length
+      name_length -= 1 if negative
+
       case current_char
       when 'i'
         consume_int_suffix
+        check_integer_literal_fits_in_size string_value, name_length, negative, start
       when 'u'
         consume_uint_suffix
+        check_integer_literal_fits_in_size string_value, name_length, negative, start
       else
         @token.number_kind = :i32
+        deduce_integer_kind string_value, name_length, negative, start
       end
+
+      @token.type = :NUMBER
+      @token.value = string_value
     end
 
     def consume_int_suffix