Skip to content

Commit

Permalink
bugfix: improve error message to include object fields (#4002)
Browse files Browse the repository at this point in the history
Fixes a bug in error reporting that caused moc to fail to report the expected type of a record pattern, eliding all fields.

Before:
```
[nix-shell:~/clean/motoko/src]$ rlwrap moc
Motoko compiler (source 0.9.1-7-gcf341ee2b)
> func f( {z:Nat} : {x:Nat; y:Bool}) {};
stdin:1.10-1.15: type error [M0119], object field z is not contained in expected type
  {}
> func f( {z:Nat} : {x:Nat; y:Bool}) {};
```

After:
```
[nix-shell:~/clean/motoko/src]$ rlwrap moc
Motoko compiler (source 0.9.1-7-gcf341ee2b-dirty)
> func f( {z:Nat} : {x:Nat; y:Bool}) {};
stdin:1.10-1.15: type error [M0119], object field z is not contained in expected type
  {x : Nat; y : Bool}
> 
```
  • Loading branch information
crusso authored Jun 30, 2023
1 parent f57636b commit 6d77f31
Show file tree
Hide file tree
Showing 3 changed files with 417 additions and 9 deletions.
14 changes: 7 additions & 7 deletions src/mo_frontend/typing.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2012,7 +2012,7 @@ and check_pat' env t pat : Scope.val_env =
if not env.pre && s = T.Actor then
local_error env pat.at "M0114" "object pattern cannot consume actor type%a"
display_typ_expand t;
check_pat_fields env s tfs pfs' T.Env.empty pat.at
check_pat_fields env t tfs pfs' T.Env.empty pat.at
| OptP pat1 ->
let t1 = try T.as_opt_sub t with Invalid_argument _ ->
error env pat.at "M0115" "option pattern cannot consume expected type%a"
Expand Down Expand Up @@ -2095,20 +2095,20 @@ and check_pats env ts pats ve at : Scope.val_env =
in
go ts pats ve

and check_pat_fields env s tfs pfs ve at : Scope.val_env =
and check_pat_fields env t tfs pfs ve at : Scope.val_env =
match tfs, pfs with
| _, [] -> ve
| [], pf::_ ->
error env pf.at "M0119"
"object field %s is not contained in expected type%a"
pf.it.id.it
display_typ (T.Obj (s, tfs))
display_typ_expand t
| T.{lab; typ = Typ _; _}::tfs', _ -> (* TODO: remove the namespace hack *)
check_pat_fields env s tfs' pfs ve at
check_pat_fields env t tfs' pfs ve at
| T.{lab; typ; depr}::tfs', pf::pfs' ->
match compare pf.it.id.it lab with
| -1 -> check_pat_fields env s [] pfs ve at
| +1 -> check_pat_fields env s tfs' pfs ve at
| -1 -> check_pat_fields env t [] pfs ve at
| +1 -> check_pat_fields env t tfs' pfs ve at
| _ ->
if T.is_mut typ then
error env pf.at "M0120" "cannot pattern match mutable field %s" lab;
Expand All @@ -2119,7 +2119,7 @@ and check_pat_fields env s tfs pfs ve at : Scope.val_env =
match pfs' with
| pf'::_ when pf'.it.id.it = lab ->
error env pf'.at "M0121" "duplicate field %s in object pattern" lab
| _ -> check_pat_fields env s tfs' pfs' ve' at
| _ -> check_pat_fields env t tfs' pfs' ve' at

and compare_pat_field pf1 pf2 = compare pf1.it.id.it pf2.it.id.it

Expand Down
206 changes: 205 additions & 1 deletion test/fail/ok/no-timer-canc.tc.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,206 @@
no-timer-canc.mo:3.10-3.21: type error [M0119], object field cancelTimer is not contained in expected type
module {}
module {
type ErrorCode =
{
#call_error : {err_code : Nat32};
#canister_error;
#canister_reject;
#destination_invalid;
#future : Nat32;
#system_fatal;
#system_transient
};
Array_init : <T>(Nat, T) -> [var T];
Array_tabulate : <T>(Nat, Nat -> T) -> [T];
Types :
module {
type Any = Any;
type Blob = Blob;
type Bool = Bool;
type Char = Char;
type Error = Error;
type Float = Float;
type Int = Int;
type Int16 = Int16;
type Int32 = Int32;
type Int64 = Int64;
type Int8 = Int8;
type Nat = Nat;
type Nat16 = Nat16;
type Nat32 = Nat32;
type Nat64 = Nat64;
type Nat8 = Nat8;
type None = None;
type Null = Null;
type Principal = Principal;
type Text = Text
};
abs : Int -> Nat;
arccos : Float -> Float;
arcsin : Float -> Float;
arctan : Float -> Float;
arctan2 : (Float, Float) -> Float;
arrayMutToBlob : [var Nat8] -> Blob;
arrayToBlob : [Nat8] -> Blob;
blobCompare : (Blob, Blob) -> Int8;
blobOfPrincipal : Principal -> Blob;
blobToArray : Blob -> [Nat8];
blobToArrayMut : Blob -> [var Nat8];
btstInt16 : (Int16, Int16) -> Bool;
btstInt32 : (Int32, Int32) -> Bool;
btstInt64 : (Int64, Int64) -> Bool;
btstInt8 : (Int8, Int8) -> Bool;
btstNat16 : (Nat16, Nat16) -> Bool;
btstNat32 : (Nat32, Nat32) -> Bool;
btstNat64 : (Nat64, Nat64) -> Bool;
btstNat8 : (Nat8, Nat8) -> Bool;
call_raw : (Principal, Text, Blob) -> async Blob;
canisterVersion : () -> Nat64;
charIsAlphabetic : Char -> Bool;
charIsLowercase : Char -> Bool;
charIsUppercase : Char -> Bool;
charIsWhitespace : Char -> Bool;
charToLower : Char -> Char;
charToNat32 : Char -> Nat32;
charToText : Char -> Text;
charToUpper : Char -> Char;
clzInt16 : Int16 -> Int16;
clzInt32 : Int32 -> Int32;
clzInt64 : Int64 -> Int64;
clzInt8 : Int8 -> Int8;
clzNat16 : Nat16 -> Nat16;
clzNat32 : Nat32 -> Nat32;
clzNat64 : Nat64 -> Nat64;
clzNat8 : Nat8 -> Nat8;
cos : Float -> Float;
createActor : (Blob, Blob) -> async Principal;
ctzInt16 : Int16 -> Int16;
ctzInt32 : Int32 -> Int32;
ctzInt64 : Int64 -> Int64;
ctzInt8 : Int8 -> Int8;
ctzNat16 : Nat16 -> Nat16;
ctzNat32 : Nat32 -> Nat32;
ctzNat64 : Nat64 -> Nat64;
ctzNat8 : Nat8 -> Nat8;
cyclesAccept : Nat -> Nat;
cyclesAdd : Nat -> ();
cyclesAvailable : () -> Nat;
cyclesBalance : () -> Nat;
cyclesRefunded : () -> Nat;
debugPrint : Text -> ();
debugPrintChar : Char -> ();
debugPrintInt : Int -> ();
debugPrintNat : Nat -> ();
decodeUtf8 : Blob -> ?Text;
encodeUtf8 : Text -> Blob;
error : Text -> Error;
errorCode : Error -> ErrorCode;
errorMessage : Error -> Text;
exp : Float -> Float;
floatAbs : Float -> Float;
floatCeil : Float -> Float;
floatCopySign : (Float, Float) -> Float;
floatFloor : Float -> Float;
floatMax : (Float, Float) -> Float;
floatMin : (Float, Float) -> Float;
floatNearest : Float -> Float;
floatSqrt : Float -> Float;
floatToFormattedText : (Float, Nat8, Nat8) -> Text;
floatToInt : Float -> Int;
floatToInt64 : Float -> Int64;
floatToText : Float -> Text;
floatTrunc : Float -> Float;
getCertificate : () -> ?Blob;
hashBlob : Blob -> Nat32;
idlHash : Text -> Nat32;
int16ToInt : Int16 -> Int;
int16ToNat16 : Int16 -> Nat16;
int32ToInt : Int32 -> Int;
int32ToNat32 : Int32 -> Nat32;
int64ToFloat : Int64 -> Float;
int64ToInt : Int64 -> Int;
int64ToNat64 : Int64 -> Nat64;
int8ToInt : Int8 -> Int;
int8ToNat8 : Int8 -> Nat8;
intToFloat : Int -> Float;
intToInt16 : Int -> Int16;
intToInt16Wrap : Int -> Int16;
intToInt32 : Int -> Int32;
intToInt32Wrap : Int -> Int32;
intToInt64 : Int -> Int64;
intToInt64Wrap : Int -> Int64;
intToInt8 : Int -> Int8;
intToInt8Wrap : Int -> Int8;
intToNat16Wrap : Int -> Nat16;
intToNat32Wrap : Int -> Nat32;
intToNat64Wrap : Int -> Nat64;
intToNat8Wrap : Int -> Nat8;
isController : Principal -> Bool;
log : Float -> Float;
nat16ToInt16 : Nat16 -> Int16;
nat16ToNat : Nat16 -> Nat;
nat32ToChar : Nat32 -> Char;
nat32ToInt32 : Nat32 -> Int32;
nat32ToNat : Nat32 -> Nat;
nat64ToInt64 : Nat64 -> Int64;
nat64ToNat : Nat64 -> Nat;
nat8ToInt8 : Nat8 -> Int8;
nat8ToNat : Nat8 -> Nat;
natToNat16 : Nat -> Nat16;
natToNat32 : Nat -> Nat32;
natToNat64 : Nat -> Nat64;
natToNat8 : Nat -> Nat8;
performanceCounter : Nat32 -> Nat64;
popcntInt16 : Int16 -> Int16;
popcntInt32 : Int32 -> Int32;
popcntInt64 : Int64 -> Int64;
popcntInt8 : Int8 -> Int8;
popcntNat16 : Nat16 -> Nat16;
popcntNat32 : Nat32 -> Nat32;
popcntNat64 : Nat64 -> Nat64;
popcntNat8 : Nat8 -> Nat8;
principalOfActor : (actor {}) -> Principal;
principalOfBlob : Blob -> Principal;
rts_callback_table_count : () -> Nat;
rts_callback_table_size : () -> Nat;
rts_collector_instructions : () -> Nat;
rts_heap_size : () -> Nat;
rts_max_live_size : () -> Nat;
rts_max_stack_size : () -> Nat;
rts_memory_size : () -> Nat;
rts_mutator_instructions : () -> Nat;
rts_reclaimed : () -> Nat;
rts_total_allocation : () -> Nat;
rts_version : () -> Text;
setCertifiedData : Blob -> ();
shiftLeft : (Nat, Nat32) -> Nat;
shiftRight : (Nat, Nat32) -> Nat;
sin : Float -> Float;
stableMemoryGrow : Nat64 -> Nat64;
stableMemoryLoadBlob : (Nat64, Nat) -> Blob;
stableMemoryLoadFloat : Nat64 -> Float;
stableMemoryLoadInt16 : Nat64 -> Int16;
stableMemoryLoadInt32 : Nat64 -> Int32;
stableMemoryLoadInt64 : Nat64 -> Int64;
stableMemoryLoadInt8 : Nat64 -> Int8;
stableMemoryLoadNat16 : Nat64 -> Nat16;
stableMemoryLoadNat32 : Nat64 -> Nat32;
stableMemoryLoadNat64 : Nat64 -> Nat64;
stableMemoryLoadNat8 : Nat64 -> Nat8;
stableMemorySize : () -> Nat64;
stableMemoryStoreBlob : (Nat64, Blob) -> ();
stableMemoryStoreFloat : (Nat64, Float) -> ();
stableMemoryStoreInt16 : (Nat64, Int16) -> ();
stableMemoryStoreInt32 : (Nat64, Int32) -> ();
stableMemoryStoreInt64 : (Nat64, Int64) -> ();
stableMemoryStoreInt8 : (Nat64, Int8) -> ();
stableMemoryStoreNat16 : (Nat64, Nat16) -> ();
stableMemoryStoreNat32 : (Nat64, Nat32) -> ();
stableMemoryStoreNat64 : (Nat64, Nat64) -> ();
stableMemoryStoreNat8 : (Nat64, Nat8) -> ();
stableVarQuery : () -> shared query () -> async {size : Nat64};
tan : Float -> Float;
textCompare : (Text, Text) -> Int8;
time : () -> Nat64;
trap : Text -> None
}
Loading

0 comments on commit 6d77f31

Please sign in to comment.