@@ -389,22 +389,25 @@ defmodule Module.Types.Of do
389389 type = specifier_type ( kind , right )
390390 expr = { :<<>> , meta , args }
391391
392- { _type , context } =
392+ { actual , context } =
393393 case kind do
394394 :match ->
395395 Module.Types.Pattern . of_match_var ( left , type , expr , stack , context )
396396
397397 :guard ->
398- { actual , context } = Module.Types.Pattern . of_guard ( left , type , expr , stack , context )
399- compatible ( actual , type , expr , stack , context )
398+ Module.Types.Pattern . of_guard ( left , type , expr , stack , context )
400399
401400 :expr ->
402401 left = annotate_interpolation ( left , right )
403- { actual , context } = Module.Types.Expr . of_expr ( left , type , expr , stack , context )
404- compatible ( actual , type , expr , stack , context )
402+ Module.Types.Expr . of_expr ( left , type , expr , stack , context )
405403 end
406404
407- specifier_size ( kind , right , stack , context )
405+ if compatible? ( actual , type ) do
406+ specifier_size ( kind , right , stack , context )
407+ else
408+ error = { :badbinary , kind , meta , expr , type , actual , context }
409+ error ( error , meta , stack , context )
410+ end
408411 end
409412
410413 defp annotate_interpolation (
@@ -441,21 +444,28 @@ defmodule Module.Types.Of do
441444 defp specifier_size ( :expr , { :size , _ , [ arg ] } = expr , stack , context )
442445 when not is_integer ( arg ) do
443446 { actual , context } = Module.Types.Expr . of_expr ( arg , integer ( ) , expr , stack , context )
444- { _ , context } = compatible ( actual , integer ( ) , expr , stack , context )
445- context
447+ compatible_size ( actual , expr , stack , context )
446448 end
447449
448450 defp specifier_size ( _pattern_or_guard , { :size , _ , [ arg ] } = expr , stack , context )
449451 when not is_integer ( arg ) do
450452 { actual , context } = Module.Types.Pattern . of_guard ( arg , integer ( ) , expr , stack , context )
451- { _ , context } = compatible ( actual , integer ( ) , expr , stack , context )
452- context
453+ compatible_size ( actual , expr , stack , context )
453454 end
454455
455456 defp specifier_size ( _kind , _specifier , _stack , context ) do
456457 context
457458 end
458459
460+ defp compatible_size ( actual , expr , stack , context ) do
461+ if compatible? ( actual , integer ( ) ) do
462+ context
463+ else
464+ error = { :badsize , expr , actual , context }
465+ error ( error , elem ( expr , 1 ) , stack , context )
466+ end
467+ end
468+
459469 ## Modules
460470
461471 @ doc """
@@ -474,39 +484,12 @@ defmodule Module.Types.Of do
474484 end
475485 end
476486
477- ## Warning helpers
478-
479- @ doc """
480- Checks if two types are compatible and emit an incompatible error if not.
481- """
482- # TODO: Consider getting rid of this and emitting precise errors instead.
483- def compatible ( actual , expected , expr , stack , context ) do
484- if compatible? ( actual , expected ) do
485- { actual , context }
486- else
487- { error_type ( ) , incompatible_error ( expr , expected , actual , stack , context ) }
488- end
489- end
490-
491- @ doc """
492- Emits incompatible types warning for the given expression.
493-
494- This is a generic warning for when the expected/actual types
495- themselves may come from several different circumstances.
496- """
497- def incompatible_error ( expr , expected_type , actual_type , stack , context ) do
498- meta = get_meta ( expr ) || stack . meta
499- hints = if meta [ :inferred_bitstring_spec ] , do: [ :inferred_bitstring_spec ] , else: [ ]
500- warning = { :incompatible , expr , expected_type , actual_type , hints , context }
501- error ( warning , meta , stack , context )
502- end
487+ ## Warning
503488
504489 defp error ( warning , meta , stack , context ) do
505490 error ( __MODULE__ , warning , meta , stack , context )
506491 end
507492
508- ## Warning formatting
509-
510493 def format_diagnostic ( { :refine_head_var , old_type , new_type , var , context } ) do
511494 traces = collect_traces ( var , context )
512495
@@ -524,15 +507,17 @@ defmodule Module.Types.Of do
524507 }
525508 end
526509
527- def format_diagnostic ( { :incompatible , expr , expected_type , actual_type , hints , context } ) do
510+ def format_diagnostic ( { :badbinary , kind , meta , expr , expected_type , actual_type , context } ) do
511+ type = if kind == :match , do: "matching" , else: "construction"
512+ hints = if meta [ :inferred_bitstring_spec ] , do: [ :inferred_bitstring_spec ] , else: [ ]
528513 traces = collect_traces ( expr , context )
529514
530515 % {
531516 details: % { typing_traces: traces } ,
532517 message:
533518 IO . iodata_to_binary ( [
534519 """
535- incompatible types in expression :
520+ incompatible types in binary #{ type } :
536521
537522 #{ expr_to_string ( expr ) |> indent ( 4 ) }
538523
@@ -550,6 +535,27 @@ defmodule Module.Types.Of do
550535 }
551536 end
552537
538+ def format_diagnostic ( { :badsize , expr , type , context } ) do
539+ traces = collect_traces ( expr , context )
540+
541+ % {
542+ details: % { typing_traces: traces } ,
543+ message:
544+ IO . iodata_to_binary ( [
545+ """
546+ expected an integer in binary size:
547+
548+ #{ expr_to_string ( expr ) |> indent ( 4 ) }
549+
550+ got type:
551+
552+ #{ to_quoted_string ( type ) |> indent ( 4 ) }
553+ """ ,
554+ format_traces ( traces )
555+ ] )
556+ }
557+ end
558+
553559 def format_diagnostic ( { :badmodule , expr , type , fun , arity , hints , context } ) do
554560 traces = collect_traces ( expr , context )
555561
0 commit comments