diagnostics.rb 10.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# frozen_string_literal: true

module Inkoc
  class Diagnostics
    include Enumerable

    attr_reader :entries

    def initialize
      @entries = []
    end

    def error(message, location)
      @entries << Diagnostic.error(message, location)
    end

    def warn(message, location)
18
      @entries << Diagnostic.warning(message, location)
19 20 21 22 23 24 25 26 27 28
    end

    def length
      @entries.length
    end

    def errors?
      @entries.any?(&:error?)
    end

29 30 31 32
    def warnings?
      @entries.any?(&:warning?)
    end

33 34 35 36 37
    def each(&block)
      @entries.each(&block)
    end

    def mutable_constant_error(location)
38
      error('Constants can not be defined as mutable', location)
39 40 41
    end

    def module_not_found_error(name, location)
42
      error("The module #{name} could not be found", location)
43 44 45
    end

    def reassign_immutable_local_error(name, location)
46 47 48 49
      error(
        "Cannot reassign immutable local variable #{name.inspect}",
        location
      )
50 51
    end

52
    def reassign_immutable_attribute_error(name, location)
53
      error("Cannot reassign immutable attribute #{name.inspect}", location)
54 55
    end

56
    def reassign_undefined_local_error(name, location)
57 58 59 60 61 62
      error(
        "Cannot reassign undefined local variable #{name.inspect}",
        location
      )

      TypeSystem::Error.new
63 64
    end

65 66
    def reassign_undefined_attribute_error(name, location)
      error("Cannot reassign undefined attribute #{name}", location)
67 68

      TypeSystem::Error.new
69 70
    end

71
    def redefine_existing_local_error(name, location)
72
      error("The local variable #{name} has already been defined", location)
73 74

      TypeSystem::Error.new
75 76
    end

77 78 79 80
    def undefined_local_error(name, location)
      error("The local variable #{name} is undefined", location)
    end

81
    def redefine_existing_attribute_error(name, location)
82
      error("The attribute #{name} has already been defined", location)
83 84

      TypeSystem::Error.new
85 86
    end

87 88
    def redefine_existing_constant_error(name, location)
      error("The constant #{name} has already been defined", location)
89 90

      TypeSystem::Error.new
91 92
    end

93 94 95 96 97 98 99
    def undefined_attribute_error(receiver, name, location)
      tname = receiver.type_name.inspect

      error(
        "The type #{tname} does not define the attribute #{name.inspect}",
        location
      )
100 101
    end

102 103 104 105 106 107 108 109
    def undefined_method_error(receiver, name, location)
      tname = receiver.type_name.inspect
      msg = name.inspect

      error(
        "The type #{tname} does not respond to the message #{msg}",
        location
      )
110 111

      TypeSystem::Error.new
112 113 114
    end

    def undefined_constant_error(name, location)
115
      error("The constant #{name} is undefined", location)
116 117

      TypeSystem::Error.new
118 119 120
    end

    def unknown_raw_instruction_error(name, location)
121 122 123 124
      error("The raw instruction #{name} does not exist", location)
    end

    def reopen_invalid_object_error(name, location)
125
      error("Cannot reopen #{name} since it's not an object", location)
126 127

      TypeSystem::Error.new
128 129 130 131
    end

    def define_required_method_on_non_trait_error(location)
      error('Required methods can only be defined on traits', location)
132
    end
133 134

    def type_error(expected, found, location)
135 136
      exp_name = expected.type_name.inspect
      found_name = found.type_name.inspect
137 138 139 140 141

      error(
        "Expected a value of type #{exp_name} instead of #{found_name}",
        location
      )
142 143

      TypeSystem::Error.new
144 145
    end

146
    def return_type_error(expected, found, location)
147 148
      exname = expected.type_name.inspect
      fname = found.type_name.inspect
149 150 151 152 153 154 155

      error(
        "Expected a value of type #{exname} to be returned instead of #{fname}",
        location
      )
    end

156 157 158
    def too_many_type_parameters(max, given, location)
      params = max == 1 ? 'parameter' : 'parameters'
      were = given == 1 ? 'is' : 'are'
159 160

      error(
161 162
        "This method takes up to #{max} type #{params}, " \
          "but #{given} #{were} given",
163 164
        location
      )
165 166

      TypeSystem::Error.new
167
    end
168 169 170 171

    def invalid_compiler_option(key, location)
      error("#{key} is not a valid compiler option", location)
    end
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

    def uninplemented_trait_error(trait, object, required_trait, location)
      tname = trait.type_name.inspect
      oname = object.type_name.inspect
      rname = required_trait.type_name.inspect

      error(
        "The trait #{tname} can not be implemented for the type #{oname} " \
          "because it does not implement the trait #{rname}",
        location
      )
    end

    def unimplemented_method_error(method, object, location)
      mname = method.type_name.inspect
      oname = object.type_name.inspect

      error(
        "The method #{mname} must be implemented by type #{oname}",
        location
      )
    end
194

195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    def argument_count_error(given, range, location)
      given_word = given == 1 ? 'was' : 'were'

      exp_word, exp_val =
        if given < range.min
          ['requires', range.min]
        else
          ['takes up to', range.max]
        end

      arg_word = exp_val == 1 ? 'argument' : 'arguments'

      error(
        "This message #{exp_word} #{exp_val} #{arg_word} " \
          "but #{given} #{given_word} given",
        location
      )
212 213 214 215 216 217 218 219 220 221 222

      TypeSystem::Error.new
    end

    def type_parameter_count_error(given, exp, location)
      error(
        "This type requires #{exp} type parameters, but #{given} were given",
        location
      )

      TypeSystem::Error.new
223
    end
224

225 226 227 228
    def undefined_keyword_argument_error(name, receiver, method, location)
      mname = method.name.inspect
      tname = receiver.type_name.inspect
      aname = name.inspect
229 230

      error(
231 232
        "The message #{mname} for type #{tname} does not support " \
          "an argument with the name #{aname}",
233 234
        location
      )
235 236

      TypeSystem::Error.new
237
    end
238 239 240 241 242 243 244

    def redefine_reserved_constant_error(name, location)
      error(
        "The reserved constant #{name.inspect} cannot be redefined",
        location
      )
    end
245 246 247 248 249 250

    def throw_without_throw_defined_error(type, location)
      tname = type.type_name.inspect

      error(
        "cannot throw a value of type #{tname} because the enclosing " \
251
          'method does not define a type to throw',
252 253 254 255 256 257 258 259 260 261 262 263 264 265
        location
      )
    end

    def throw_at_top_level_error(type, location)
      tname = type.type_name.inspect

      error("cannot throw a value of type #{tname} at the top-level", location)
    end

    def missing_throw_error(throw_type, location)
      tname = throw_type.type_name.inspect

      error(
266
        "this block is expected to throw a value of type #{tname} " \
267 268 269 270
          'but no value is ever thrown',
        location
      )
    end
271 272 273 274 275 276 277 278 279 280

    def missing_try_error(throw_type, location)
      tname = throw_type.type_name.inspect

      error(
        "This message may throw a value of type #{tname} but the `try` " \
          'statement is missing',
        location
      )
    end
281

282 283 284 285
    def redundant_try_warning(location)
      warn('This expression will never throw a value', location)
    end

286 287 288 289 290 291
    def define_instance_attribute_error(name, location)
      error(
        "Instance attributes such as #{name.inspect} can only be " \
          'defined in a constructor method',
        location
      )
292 293

      TypeSystem::Error.new
294
    end
295 296 297 298 299 300 301 302 303 304 305

    def import_undefined_symbol_error(mname, sname, location)
      error("The module #{mname} does not define #{sname.inspect}", location)
    end

    def import_existing_symbol_error(sname, location)
      error(
        "The symbol #{sname.inspect} can not be imported as it already exists",
        location
      )
    end
306 307 308

    def invalid_type_parameters(type, given, location)
      name = type.name.inspect
309
      ex = type.type_parameters.map(&:name).join(', ')
310 311 312 313 314 315 316
      got = given.join(', ')

      error(
        "The type #{name} requires type parameters [#{ex}] instead of [#{got}]",
        location
      )
    end
317 318 319 320 321 322 323 324

    def shadowing_type_parameter_error(name, location)
      error(
        "The type parameter #{name} shadows another type parameter with the " \
          'same name',
        location
      )
    end
325

326
    def extend_trait_error(type, location)
327 328 329
      tname = type.type_name

      error(
330
        "The trait #{tname} can not be extended because it is not empty",
331 332
        location
      )
333 334

      TypeSystem::Error.new
335
    end
336 337 338 339 340 341

    def dereference_error(type, location)
      tname = type.type_name

      error("The type #{tname} is not an optional type", location)
    end
342

343 344
    def method_requirement_error(receiver, block_type, value_type, bound, loc)
      rname = receiver.type_name.inspect
345 346
      bname = block_type.type_name.inspect
      vname = value_type.type_name.inspect
347
      req = bound.required_traits.map(&:type_name).join(', ')
348 349

      error(
350 351 352
        "The method #{bname} for #{rname} is only available when #{vname} " \
          "implements the following trait(s): #{req}",
        loc
353 354
      )
    end
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394

    def invalid_type_parameter_requirement(type, location)
      error(
        "The type #{type.type_name.inspect} can not be used as a " \
          'type parameter requirement because it is not a trait',
        location
      )
    end

    def undefined_type_parameter_error(type, name, location)
      tname = type.type_name.inspect

      error(
        "The type #{tname} does not define the type parameter #{name.inspect}",
        location
      )

      TypeSystem::Error.new
    end

    def return_outside_of_method_error(location)
      error('The "return" keyword can only be used inside a method', location)
    end

    def invalid_cast_error(from, to, location)
      fname = from.type_name.inspect
      tname = to.type_name.inspect

      error("The type #{fname} can not be casted to #{tname}", location)

      TypeSystem::Error.new
    end

    def incompatible_optional_method(rec_type, nil_type, name, location)
      rec_impl = rec_type.lookup_method(name).type.type_name.inspect
      nil_impl = nil_type.lookup_method(name).type.type_name.inspect
      nname = nil_type.type_name.inspect
      rname = rec_type.type_name.inspect

      error(
395
        "The message #{name.inspect} can not be sent to a #{rname} " \
396 397 398 399 400 401 402
          "because its implementation (#{rec_impl}) is not compatible with " \
          "the implementation of #{nname} (#{nil_impl})",
        location
      )

      TypeSystem::Error.new
    end
403 404
  end
end