Skip to content

Commit

Permalink
Compiler: added --error-trace to show a complete error trace.
Browse files Browse the repository at this point in the history
Hide traces like "Nil trace" and other traces by default, which
makes understanding errors much harder, but still allow to
show them with a flag.
Ary Borenszweig committed Sep 15, 2016
1 parent f021f1f commit 611849c
Showing 7 changed files with 30 additions and 9 deletions.
4 changes: 4 additions & 0 deletions src/compiler/crystal/command.cr
Original file line number Diff line number Diff line change
@@ -304,6 +304,10 @@ class Crystal::Command
output_format = f
end

opts.on("--error-trace", "Show full error trace") do
compiler.show_error_trace = true
end

opts.on("-h", "--help", "Show this message") do
puts opts
exit
3 changes: 3 additions & 0 deletions src/compiler/crystal/command/spec.cr
Original file line number Diff line number Diff line change
@@ -19,6 +19,9 @@ class Crystal::Command
opts.on("-D FLAG", "--define FLAG", "Define a compile-time flag") do |flag|
compiler.flags << flag
end
opts.on("--error-trace", "Show full error trace") do
compiler.show_error_trace = true
end
opts.on("--release", "Compile in release mode") do
compiler.release = true
end
4 changes: 4 additions & 0 deletions src/compiler/crystal/compiler.cr
Original file line number Diff line number Diff line change
@@ -106,6 +106,9 @@ module Crystal
# Default standard error to use in a compilation.
property stderr : IO = STDERR

# Whether to show error trace
property? show_error_trace = false

# Compiles the given *source*, with *output_filename* as the name
# of the generated executable.
#
@@ -150,6 +153,7 @@ module Crystal
program.wants_doc = wants_doc?
program.color = color?
program.stdout = stdout
program.show_error_trace = show_error_trace?
program
end

3 changes: 3 additions & 0 deletions src/compiler/crystal/program.cr
Original file line number Diff line number Diff line change
@@ -103,6 +103,9 @@ module Crystal
# Default standard output to use in a program, while compiling.
property stdout : IO = STDOUT

# Whether to show error trace
property? show_error_trace = false

def initialize
super(self, self, "main")

8 changes: 4 additions & 4 deletions src/compiler/crystal/semantic/bindings.cr
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@ module Crystal
# See if we can find where the mismatched type came from
if from && !ex.inner && (freeze_type = @freeze_type) && type.is_a?(UnionType) && type.includes_type?(freeze_type) && type.union_types.size == 2
other_type = type.union_types.find { |type| type != freeze_type }
trace = from.find_owner_trace(other_type)
trace = from.find_owner_trace(freeze_type.program, other_type)
ex.inner = trace
end

@@ -50,7 +50,7 @@ module Crystal
if !freeze_type.includes_type?(invalid_type.program.nil) && invalid_type.includes_type?(invalid_type.program.nil)
# This means that an instance variable become nil
if self.is_a?(MetaTypeVar) && (nil_reason = self.nil_reason)
inner = MethodTraceException.new(nil, [] of ASTNode, nil_reason)
inner = MethodTraceException.new(nil, [] of ASTNode, nil_reason, freeze_type.program.show_error_trace?)
end
end

@@ -192,7 +192,7 @@ module Crystal
type
end

def find_owner_trace(owner)
def find_owner_trace(program, owner)
owner_trace = [] of ASTNode
node = self

@@ -210,7 +210,7 @@ module Crystal
end
end

MethodTraceException.new(owner, owner_trace, nil_reason)
MethodTraceException.new(owner, owner_trace, nil_reason, program.show_error_trace?)
end
end

4 changes: 2 additions & 2 deletions src/compiler/crystal/semantic/call_error.cr
Original file line number Diff line number Diff line change
@@ -79,7 +79,7 @@ class Crystal::Call
if defs.empty?
check_macro_wrong_number_of_arguments(def_name)

owner_trace = obj.try &.find_owner_trace(owner)
owner_trace = obj.try &.find_owner_trace(owner.program, owner)
similar_name = owner.lookup_similar_def_name(def_name, self.args.size, block)

error_msg = String.build do |msg|
@@ -213,7 +213,7 @@ class Crystal::Call
end

if args.size == 1 && args.first.type.includes_type?(program.nil)
owner_trace = args.first.find_owner_trace(program.nil)
owner_trace = args.first.find_owner_trace(program, program.nil)
end

arg_names = [] of Array(String)
13 changes: 10 additions & 3 deletions src/compiler/crystal/semantic/exception.cr
Original file line number Diff line number Diff line change
@@ -157,7 +157,7 @@ module Crystal
end

class MethodTraceException < Exception
def initialize(@owner : Type?, @trace : Array(ASTNode), @nil_reason : NilReason?)
def initialize(@owner : Type?, @trace : Array(ASTNode), @nil_reason : NilReason?, @show : Bool)
super(nil)
end

@@ -174,15 +174,22 @@ module Crystal

def append_to_s(source, io)
has_trace = @trace.any?(&.location)
nil_reason = @nil_reason

if !@show && (has_trace || nil_reason)
io.print "Rerun with --error-trace to show a complete error trace."
return
end

if has_trace
io.puts ("=" * 80)
io << "\n#{@owner} trace:"
io.puts
io << "#{@owner} trace:"
@trace.each do |node|
print_with_location node, io
end
end

nil_reason = @nil_reason
return unless nil_reason

if has_trace

3 comments on commit 611849c

@asterite
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/cc @waj 😄

@waj
Copy link
Member

@waj waj commented on 611849c Sep 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay! 😉

@ozra
Copy link
Contributor

@ozra ozra commented on 611849c Sep 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Please sign in to comment.