Skip to content

Commit

Permalink
Compiler: improve error message of a failing as to include the orig…
Browse files Browse the repository at this point in the history
…inal type as well as the filename and line number. Fixes #2663
  • Loading branch information
asterite committed May 30, 2016
1 parent b3943d5 commit d5a2636
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 10 deletions.
8 changes: 4 additions & 4 deletions spec/compiler/codegen/cast_spec.cr
Expand Up @@ -48,7 +48,7 @@ describe "Code gen: cast" do
a as Char
false
rescue ex
(ex.message == "cast to Char failed") && (ex.class == TypeCastError)
ex.message.not_nil!.includes?("cast from Int32 to Char failed") && (ex.class == TypeCastError)
end
)).to_b.should be_true
end
Expand All @@ -72,7 +72,7 @@ describe "Code gen: cast" do
a as Float64 | Char
false
rescue ex
(ex.message == "cast to (Char | Float64) failed") && (ex.class == TypeCastError)
ex.message.not_nil!.includes?("cast from Int32 to (Char | Float64) failed") && (ex.class == TypeCastError)
end
)).to_b.should be_true
end
Expand Down Expand Up @@ -120,7 +120,7 @@ describe "Code gen: cast" do
a as CastSpecBaz
false
rescue ex
(ex.message == "cast to CastSpecBaz failed") && (ex.class == TypeCastError)
ex.message.not_nil!.includes?("cast from CastSpecBar to CastSpecBaz failed") && (ex.class == TypeCastError)
end
)).to_b.should be_true
end
Expand Down Expand Up @@ -187,7 +187,7 @@ describe "Code gen: cast" do
a as Nil
false
rescue ex
(ex.message.not_nil!.includes? "cast to Nil failed") && (ex.class == TypeCastError)
ex.message.not_nil!.includes?("cast from Reference to Nil failed") && (ex.class == TypeCastError)
end
)).to_b.should be_true
end
Expand Down
26 changes: 22 additions & 4 deletions src/compiler/crystal/codegen/codegen.cr
Expand Up @@ -1076,7 +1076,11 @@ module Crystal
cond cmp, matches_block, doesnt_match_block

position_at_end doesnt_match_block
accept type_cast_exception_call(to_type)

temp_var_name = @mod.new_temp_var_name
context.vars[temp_var_name] = LLVMVar.new(last_value, obj_type, already_loaded: true)
accept type_cast_exception_call(obj_type, to_type, node, temp_var_name)
context.vars.delete temp_var_name

position_at_end matches_block
@last = downcast last_value, resulting_type, obj_type, true
Expand Down Expand Up @@ -1126,11 +1130,25 @@ module Crystal
false
end

def type_cast_exception_call(to_type)
ex = Call.new(Path.global("TypeCastError"), "new", StringLiteral.new("cast to #{to_type} failed"))
def type_cast_exception_call(from_type, to_type, node, var_name)
pieces = [
StringLiteral.new("cast from "),
Call.new(Var.new(var_name), "class"),
StringLiteral.new(" to #{to_type} failed"),
] of ASTNode

if location = node.location
pieces << StringLiteral.new (", at #{location.filename}:#{location.line_number}")
end

ex = Call.new(Path.global("TypeCastError"), "new", StringInterpolation.new(pieces))
call = Call.global("raise", ex)
call = @mod.normalize(call)

@mod.visit_main call
meta_vars = MetaVars.new
meta_vars[var_name] = MetaVar.new(var_name, type: from_type)
visitor = MainVisitor.new(@mod, meta_vars)
@mod.visit_main call, visitor: visitor
call
end

Expand Down
4 changes: 2 additions & 2 deletions src/compiler/crystal/semantic/main_visitor.cr
Expand Up @@ -2,8 +2,8 @@ require "./base_type_visitor"

module Crystal
class Program
def visit_main(node)
node.accept MainVisitor.new(self)
def visit_main(node, visitor = MainVisitor.new(self))
node.accept visitor

fix_empty_types node
node = cleanup node
Expand Down

0 comments on commit d5a2636

Please sign in to comment.