dfinity / motoko

Simple high-level language for writing Internet Computer canisters

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Specify in error messages, where exactly two Actor objects differ

vporton opened this issue · comments

It is very inconvenient, when I receive a long message of two Actor classes differing. I want the message to show where (which methods with their signatures) is the point(s) of difference.

I adopted to copy the error message, extract from it two Actor classes manually and compare them with wdiff command to find what's wrong. But that's inconvenient.

cannot implicitly instantiate function of type
  <K, V>(Tree<K, V>, (K, K) -> Order, K) -> ?V
to argument of type
  ({
     #leaf;
     #node :
       (Color, Tree<(Partition__1, OuterSubDBKey), GUID__2>,
        ((Partition__1, OuterSubDBKey), ?GUID__2),
        Tree<(Partition__1, OuterSubDBKey), GUID__2>)
   },
   ((Partition__1, OuterSubDBKey), (Partition__1, OuterSubDBKey)) ->
     {#equal; #greater; #less},
   (actor {
      createOuter :
        shared {
                 innerKey : InnerSubDBKey;
                 outerKey : OuterSubDBKey;
                 part : Principal
               } ->
          async
            {
              inner : {canister : Principal; key : InnerSubDBKey};
              outer : {canister : Principal; key : OuterSubDBKey}
            };
      deleteInner : shared {innerKey : InnerSubDBKey; sk : SK} -> async ();
      deleteSubDBInner : shared {innerKey : InnerSubDBKey} -> async ();
      deleteSubDBOuter : shared {outerKey : OuterSubDBKey} -> async ();
      getByInner :
        shared query {innerKey : InnerSubDBKey; sk : SK} ->
          async ?AttributeValue;
      getByOuter :
        shared {outerKey : OuterSubDBKey; sk : SK} -> async ?AttributeValue;
      getInner :
        shared query {outerKey : OuterSubDBKey} ->
          async ?{canister : Principal; key : InnerSubDBKey};
      getSubDBUserDataInner :
        shared {innerKey : InnerSubDBKey} -> async ?Text;
      getSubDBUserDataOuter :
        shared {outerKey : OuterSubDBKey} -> async ?Text;
      hasByInner :
        shared query {innerKey : InnerSubDBKey; sk : SK} -> async Bool;
      hasByOuter : shared {outerKey : OuterSubDBKey; sk : SK} -> async Bool;
      hasSubDBByInner : shared query {innerKey : InnerSubDBKey} -> async Bool;
      hasSubDBByOuter : shared {outerKey : OuterSubDBKey} -> async Bool;
      isOverflowed : shared query () -> async Bool;
      putLocation :
        shared {
                 innerCanister : Principal;
                 innerKey : InnerSubDBKey;
                 outerKey : OuterSubDBKey
               } ->
          async ();
      rawDeleteSubDB : shared {innerKey : InnerSubDBKey} -> async ();
      rawGetSubDB :
        shared query {innerKey : InnerSubDBKey} ->
          async ?{map : [(SK, AttributeValue)]; userData : Text};
      rawInsertSubDB :
        shared {
                 hardCap : ?Nat;
                 innerKey : ?InnerSubDBKey;
                 map : [(SK, AttributeValue)];
                 userData : Text
               } ->
          async {innerKey : InnerSubDBKey};
      rawInsertSubDBAndSetOuter :
        shared {
                 hardCap : ?Nat;
                 keys : ?{innerKey : InnerSubDBKey; outerKey : OuterSubDBKey};
                 map : [(SK, AttributeValue)];
                 userData : Text
               } ->
          async {innerKey : InnerSubDBKey; outerKey : OuterSubDBKey};
      scanLimitInner :
        shared query {
                       dir : Direction__1;
                       innerKey : InnerSubDBKey;
                       limit : Nat;
                       lowerBound : SK;
                       upperBound : SK
                     } ->
          async ScanLimitResult__1<Text, AttributeValue>;
      scanLimitOuter :
        shared {
                 dir : Direction__1;
                 limit : Nat;
                 lowerBound : SK;
                 outerKey : OuterSubDBKey;
                 upperBound : SK
               } ->
          async ScanLimitResult__1<Text, AttributeValue>;
      scanSubDBs :
        shared query () ->
          async
            [(OuterSubDBKey, {canister : Principal; key : InnerSubDBKey})];
      startInsertingImpl :
        shared {innerKey : InnerSubDBKey; sk : SK; value : AttributeValue} ->
          async ();
      subDBSizeByInner :
        shared query {innerKey : InnerSubDBKey} -> async ?Nat;
      subDBSizeByOuter : shared {outerKey : OuterSubDBKey} -> async ?Nat;
      subDBSizeOuterImpl : shared {outerKey : OuterSubDBKey} -> async ?Nat;
      superDBSize : shared query () -> async Nat
    }, Nat))
because implicit instantiation of type parameter K is over-constrained with
  (actor {
     createOuter :
       shared {
                innerKey : InnerSubDBKey;
                outerKey : OuterSubDBKey;
                part : Principal
              } ->
         async
           {
             inner : {canister : Principal; key : InnerSubDBKey};
             outer : {canister : Principal; key : OuterSubDBKey}
           };
     deleteInner : shared {innerKey : InnerSubDBKey; sk : SK} -> async ();
     deleteSubDBInner : shared {innerKey : InnerSubDBKey} -> async ();
     deleteSubDBOuter : shared {outerKey : OuterSubDBKey} -> async ();
     getByInner :
       shared query {innerKey : InnerSubDBKey; sk : SK} ->
         async ?AttributeValue;
     getByOuter :
       shared {outerKey : OuterSubDBKey; sk : SK} -> async ?AttributeValue;
     getInner :
       shared query {outerKey : OuterSubDBKey} ->
         async ?{canister : Principal; key : InnerSubDBKey};
     getSubDBUserDataInner : shared {innerKey : InnerSubDBKey} -> async ?Text;
     getSubDBUserDataOuter : shared {outerKey : OuterSubDBKey} -> async ?Text;
     hasByInner :
       shared query {innerKey : InnerSubDBKey; sk : SK} -> async Bool;
     hasByOuter : shared {outerKey : OuterSubDBKey; sk : SK} -> async Bool;
     hasSubDBByInner : shared query {innerKey : InnerSubDBKey} -> async Bool;
     hasSubDBByOuter : shared {outerKey : OuterSubDBKey} -> async Bool;
     isOverflowed : shared query () -> async Bool;
     putLocation :
       shared {
                innerCanister : Principal;
                innerKey : InnerSubDBKey;
                outerKey : OuterSubDBKey
              } ->
         async ();
     rawDeleteSubDB : shared {innerKey : InnerSubDBKey} -> async ();
     rawGetSubDB :
       shared query {innerKey : InnerSubDBKey} ->
         async ?{map : [(SK, AttributeValue)]; userData : Text};
     rawInsertSubDB :
       shared {
                hardCap : ?Nat;
                innerKey : ?InnerSubDBKey;
                map : [(SK, AttributeValue)];
                userData : Text
              } ->
         async {innerKey : InnerSubDBKey};
     rawInsertSubDBAndSetOuter :
       shared {
                hardCap : ?Nat;
                keys : ?{innerKey : InnerSubDBKey; outerKey : OuterSubDBKey};
                map : [(SK, AttributeValue)];
                userData : Text
              } ->
         async {innerKey : InnerSubDBKey; outerKey : OuterSubDBKey};
     scanLimitInner :
       shared query {
                      dir : Direction__1;
                      innerKey : InnerSubDBKey;
                      limit : Nat;
                      lowerBound : SK;
                      upperBound : SK
                    } ->
         async ScanLimitResult__1<Text, AttributeValue>;
     scanLimitOuter :
       shared {
                dir : Direction__1;
                limit : Nat;
                lowerBound : SK;
                outerKey : OuterSubDBKey;
                upperBound : SK
              } ->
         async ScanLimitResult__1<Text, AttributeValue>;
     scanSubDBs :
       shared query () ->
         async [(OuterSubDBKey, {canister : Principal; key : InnerSubDBKey})];
     startInsertingImpl :
       shared {innerKey : InnerSubDBKey; sk : SK; value : AttributeValue} ->
         async ();
     subDBSizeByInner : shared query {innerKey : InnerSubDBKey} -> async ?Nat;
     subDBSizeByOuter : shared {outerKey : OuterSubDBKey} -> async ?Nat;
     subDBSizeOuterImpl : shared {outerKey : OuterSubDBKey} -> async ?Nat;
     superDBSize : shared query () -> async Nat
   }, OuterSubDBKey)  <: 
    K  <:  (Partition__1, OuterSubDBKey)
where
  (actor {
     createOuter :
       shared {
                innerKey : InnerSubDBKey;
                outerKey : OuterSubDBKey;
                part : Principal
              } ->
         async
           {
             inner : {canister : Principal; key : InnerSubDBKey};
             outer : {canister : Principal; key : OuterSubDBKey}
           };
     deleteInner : shared {innerKey : InnerSubDBKey; sk : SK} -> async ();
     deleteSubDBInner : shared {innerKey : InnerSubDBKey} -> async ();
     deleteSubDBOuter : shared {outerKey : OuterSubDBKey} -> async ();
     getByInner :
       shared query {innerKey : InnerSubDBKey; sk : SK} ->
         async ?AttributeValue;
     getByOuter :
       shared {outerKey : OuterSubDBKey; sk : SK} -> async ?AttributeValue;
     getInner :
       shared query {outerKey : OuterSubDBKey} ->
         async ?{canister : Principal; key : InnerSubDBKey};
     getSubDBUserDataInner : shared {innerKey : InnerSubDBKey} -> async ?Text;
     getSubDBUserDataOuter : shared {outerKey : OuterSubDBKey} -> async ?Text;
     hasByInner :
       shared query {innerKey : InnerSubDBKey; sk : SK} -> async Bool;
     hasByOuter : shared {outerKey : OuterSubDBKey; sk : SK} -> async Bool;
     hasSubDBByInner : shared query {innerKey : InnerSubDBKey} -> async Bool;
     hasSubDBByOuter : shared {outerKey : OuterSubDBKey} -> async Bool;
     isOverflowed : shared query () -> async Bool;
     putLocation :
       shared {
                innerCanister : Principal;
                innerKey : InnerSubDBKey;
                outerKey : OuterSubDBKey
              } ->
         async ();
     rawDeleteSubDB : shared {innerKey : InnerSubDBKey} -> async ();
     rawGetSubDB :
       shared query {innerKey : InnerSubDBKey} ->
         async ?{map : [(SK, AttributeValue)]; userData : Text};
     rawInsertSubDB :
       shared {
                hardCap : ?Nat;
                innerKey : ?InnerSubDBKey;
                map : [(SK, AttributeValue)];
                userData : Text
              } ->
         async {innerKey : InnerSubDBKey};
     rawInsertSubDBAndSetOuter :
       shared {
                hardCap : ?Nat;
                keys : ?{innerKey : InnerSubDBKey; outerKey : OuterSubDBKey};
                map : [(SK, AttributeValue)];
                userData : Text
              } ->
         async {innerKey : InnerSubDBKey; outerKey : OuterSubDBKey};
     scanLimitInner :
       shared query {
                      dir : Direction__1;
                      innerKey : InnerSubDBKey;
                      limit : Nat;
                      lowerBound : SK;
                      upperBound : SK
                    } ->
         async ScanLimitResult__1<Text, AttributeValue>;
     scanLimitOuter :
       shared {
                dir : Direction__1;
                limit : Nat;
                lowerBound : SK;
                outerKey : OuterSubDBKey;
                upperBound : SK
              } ->
         async ScanLimitResult__1<Text, AttributeValue>;
     scanSubDBs :
       shared query () ->
         async [(OuterSubDBKey, {canister : Principal; key : InnerSubDBKey})];
     startInsertingImpl :
       shared {innerKey : InnerSubDBKey; sk : SK; value : AttributeValue} ->
         async ();
     subDBSizeByInner : shared query {innerKey : InnerSubDBKey} -> async ?Nat;
     subDBSizeByOuter : shared {outerKey : OuterSubDBKey} -> async ?Nat;
     subDBSizeOuterImpl : shared {outerKey : OuterSubDBKey} -> async ?Nat;
     superDBSize : shared query () -> async Nat
   }, OuterSubDBKey)  </: 
    (Partition__1, OuterSubDBKey)
so that no valid instantiation exists

I feel your pain.

(Note to self: to address this properly we have to extend our subtyping check to not just return a bool but, in the failure case, a path indicating which subgoal during subtying failed. Moscow ML does something similar at the module level.)