mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-20 23:37:56 +03:00
Syntactic ability links in solve
This commit is contained in:
parent
4d0c1e6a9c
commit
d2da395619
@ -8,6 +8,7 @@ interface Json
|
||||
Str,
|
||||
Encode.{
|
||||
Encoder,
|
||||
EncoderFormatting,
|
||||
custom,
|
||||
appendWith,
|
||||
u8,
|
||||
@ -31,7 +32,7 @@ interface Json
|
||||
},
|
||||
]
|
||||
|
||||
Json := {}
|
||||
Json := {} has [EncoderFormatting {u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64, dec, bool, string, list, record, tag}]
|
||||
|
||||
toUtf8 = @Json {}
|
||||
|
||||
|
@ -445,13 +445,19 @@ fn canonicalize_claimed_ability_impl<'a>(
|
||||
name: label_str.to_owned(),
|
||||
region,
|
||||
});
|
||||
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
match scope.lookup_ability_member_shadow(member_symbol) {
|
||||
Some(symbol) => {
|
||||
return Ok((member_symbol, symbol));
|
||||
Some(impl_symbol) => {
|
||||
// TODO: get rid of register_specializing_symbol
|
||||
scope
|
||||
.abilities_store
|
||||
.register_specializing_symbol(impl_symbol, member_symbol);
|
||||
|
||||
Ok((member_symbol, impl_symbol))
|
||||
}
|
||||
None => {
|
||||
env.problem(Problem::ImplementationNotFound {
|
||||
|
@ -327,10 +327,6 @@ impl Scope {
|
||||
Err((loc_original_shadow.region, shadow, shadow_symbol))
|
||||
}
|
||||
None => {
|
||||
// TODO: remove register_specializing_symbol
|
||||
self.abilities_store
|
||||
.register_specializing_symbol(shadow_symbol, original_symbol);
|
||||
|
||||
self.shadows
|
||||
.insert(original_symbol, Loc::at(region, shadow_symbol));
|
||||
|
||||
|
@ -5940,7 +5940,7 @@ mod solve_expr {
|
||||
|
||||
Hash has hash : a -> U64 | a has Hash
|
||||
|
||||
Id := U64
|
||||
Id := U64 has [Hash {hash}]
|
||||
|
||||
hash = \@Id n -> n
|
||||
"#
|
||||
@ -5960,7 +5960,7 @@ mod solve_expr {
|
||||
hash : a -> U64 | a has Hash
|
||||
hash32 : a -> U32 | a has Hash
|
||||
|
||||
Id := U64
|
||||
Id := U64 has [Hash {hash, hash32}]
|
||||
|
||||
hash = \@Id n -> n
|
||||
hash32 = \@Id n -> Num.toU32 n
|
||||
@ -5985,7 +5985,7 @@ mod solve_expr {
|
||||
eq : a, a -> Bool | a has Ord
|
||||
le : a, a -> Bool | a has Ord
|
||||
|
||||
Id := U64
|
||||
Id := U64 has [Hash {hash, hash32}, Ord {eq, le}]
|
||||
|
||||
hash = \@Id n -> n
|
||||
hash32 = \@Id n -> Num.toU32 n
|
||||
@ -6013,7 +6013,7 @@ mod solve_expr {
|
||||
Hash has
|
||||
hash : a -> U64 | a has Hash
|
||||
|
||||
Id := U64
|
||||
Id := U64 has [Hash {hash}]
|
||||
|
||||
hash : Id -> U64
|
||||
hash = \@Id n -> n
|
||||
@ -6033,7 +6033,7 @@ mod solve_expr {
|
||||
Hash has
|
||||
hash : a -> U64 | a has Hash
|
||||
|
||||
Id := U64
|
||||
Id := U64 has [Hash {hash}]
|
||||
|
||||
hash : Id -> U64
|
||||
"#
|
||||
@ -6052,7 +6052,7 @@ mod solve_expr {
|
||||
Hash has
|
||||
hash : a -> U64 | a has Hash
|
||||
|
||||
Id := U64
|
||||
Id := U64 has [Hash {hash}]
|
||||
|
||||
hash = \@Id n -> n
|
||||
|
||||
@ -6146,7 +6146,7 @@ mod solve_expr {
|
||||
|
||||
hashEq = \x, y -> hash x == hash y
|
||||
|
||||
Id := U64
|
||||
Id := U64 has [Hash {hash}]
|
||||
hash = \@Id n -> n
|
||||
|
||||
result = hashEq (@Id 100) (@Id 101)
|
||||
@ -6331,15 +6331,13 @@ mod solve_expr {
|
||||
toBytes = \val, fmt -> appendWith [] (toEncoder val) fmt
|
||||
|
||||
|
||||
Linear := {}
|
||||
Linear := {} has [Format {u8}]
|
||||
|
||||
# impl Format for Linear
|
||||
u8 = \n -> @Encoder (\lst, @Linear {} -> List.append lst n)
|
||||
#^^{-1}
|
||||
|
||||
MyU8 := U8
|
||||
MyU8 := U8 has [Encoding {toEncoder}]
|
||||
|
||||
# impl Encoding for MyU8
|
||||
toEncoder = \@MyU8 n -> u8 n
|
||||
#^^^^^^^^^{-1}
|
||||
|
||||
@ -6385,18 +6383,16 @@ mod solve_expr {
|
||||
Err e -> Err e
|
||||
|
||||
|
||||
Linear := {}
|
||||
Linear := {} has [DecoderFormatting {u8}]
|
||||
|
||||
# impl DecoderFormatting for Linear
|
||||
u8 = @Decoder \lst, @Linear {} ->
|
||||
#^^{-1}
|
||||
when List.first lst is
|
||||
Ok n -> { result: Ok n, rest: List.dropFirst lst }
|
||||
Err _ -> { result: Err TooShort, rest: [] }
|
||||
|
||||
MyU8 := U8
|
||||
MyU8 := U8 has [Decoder {decoder}]
|
||||
|
||||
# impl Decoding for MyU8
|
||||
decoder = @Decoder \lst, fmt ->
|
||||
#^^^^^^^{-1}
|
||||
when decodeWith lst u8 fmt is
|
||||
@ -6446,7 +6442,7 @@ mod solve_expr {
|
||||
|
||||
Default has default : {} -> a | a has Default
|
||||
|
||||
A := {}
|
||||
A := {} has [Default {default}]
|
||||
default = \{} -> @A {}
|
||||
|
||||
main =
|
||||
@ -6466,10 +6462,10 @@ mod solve_expr {
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
imports [Encode.{ toEncoder }, Json]
|
||||
imports [Encode.{ Encoding, toEncoder }, Json]
|
||||
provides [main] to "./platform"
|
||||
|
||||
HelloWorld := {}
|
||||
HelloWorld := {} has [Encoding {toEncoder}]
|
||||
|
||||
toEncoder = \@HelloWorld {} ->
|
||||
Encode.custom \bytes, fmt ->
|
||||
@ -6538,7 +6534,7 @@ mod solve_expr {
|
||||
|
||||
Id has id : a -> a | a has Id
|
||||
|
||||
A := {}
|
||||
A := {} has [Id {id}]
|
||||
id = \@A {} -> @A {}
|
||||
#^^{-1}
|
||||
|
||||
@ -6574,7 +6570,7 @@ mod solve_expr {
|
||||
Id1 has id1 : a -> a | a has Id1
|
||||
Id2 has id2 : a -> a | a has Id2
|
||||
|
||||
A := {}
|
||||
A := {} has [Id1 {id1}, Id2 {id2}]
|
||||
id1 = \@A {} -> @A {}
|
||||
#^^^{-1}
|
||||
|
||||
@ -6607,7 +6603,7 @@ mod solve_expr {
|
||||
|
||||
Id has id : a -> a | a has Id
|
||||
|
||||
A := {}
|
||||
A := {} has [Id {id}]
|
||||
id = \@A {} -> @A {}
|
||||
#^^{-1}
|
||||
|
||||
@ -6645,7 +6641,7 @@ mod solve_expr {
|
||||
|
||||
Id has id : a -> a | a has Id
|
||||
|
||||
A := {}
|
||||
A := {} has [Id {id}]
|
||||
id = \@A {} -> @A {}
|
||||
#^^{-1}
|
||||
|
||||
@ -6681,7 +6677,7 @@ mod solve_expr {
|
||||
|
||||
Id has id : a -> Thunk a | a has Id
|
||||
|
||||
A := {}
|
||||
A := {} has [Id {id}]
|
||||
id = \@A {} -> \{} -> @A {}
|
||||
#^^{-1}
|
||||
|
||||
@ -6716,7 +6712,7 @@ mod solve_expr {
|
||||
|
||||
Id has id : a -> Thunk a | a has Id
|
||||
|
||||
A := {}
|
||||
A := {} has [Id {id}]
|
||||
id = \@A {} -> @Thunk (\{} -> @A {})
|
||||
#^^{-1}
|
||||
|
||||
@ -6746,7 +6742,7 @@ mod solve_expr {
|
||||
|
||||
Id has id : a -> Thunk a | a has Id
|
||||
|
||||
A := {}
|
||||
A := {} has [Id {id}]
|
||||
id = \@A {} -> \{} -> @A {}
|
||||
#^^{-1}
|
||||
|
||||
@ -6775,7 +6771,7 @@ mod solve_expr {
|
||||
|
||||
Diverge has diverge : a -> a | a has Diverge
|
||||
|
||||
A := {}
|
||||
A := {} has [Diverge {diverge}]
|
||||
diverge = \@A {} -> diverge (@A {})
|
||||
#^^^^^^^{-1} ^^^^^^^
|
||||
|
||||
@ -6806,7 +6802,7 @@ mod solve_expr {
|
||||
ping : a -> a | a has Bounce
|
||||
pong : a -> a | a has Bounce
|
||||
|
||||
A := {}
|
||||
A := {} has [Bounce {ping, pong}]
|
||||
|
||||
ping = \@A {} -> pong (@A {})
|
||||
#^^^^{-1} ^^^^
|
||||
@ -7109,11 +7105,11 @@ mod solve_expr {
|
||||
F has f : a -> (b -> {}) | a has F, b has G
|
||||
G has g : b -> {} | b has G
|
||||
|
||||
Fo := {}
|
||||
Fo := {} has [F {f}]
|
||||
f = \@Fo {} -> g
|
||||
#^{-1}
|
||||
|
||||
Go := {}
|
||||
Go := {} has [G {g}]
|
||||
g = \@Go {} -> {}
|
||||
#^{-1}
|
||||
|
||||
@ -7141,11 +7137,11 @@ mod solve_expr {
|
||||
F has f : a -> ({} -> b) | a has F, b has G
|
||||
G has g : {} -> b | b has G
|
||||
|
||||
Fo := {}
|
||||
Fo := {} has [F {f}]
|
||||
f = \@Fo {} -> g
|
||||
#^{-1}
|
||||
|
||||
Go := {}
|
||||
Go := {} has [G {g}]
|
||||
g = \{} -> @Go {}
|
||||
#^{-1}
|
||||
|
||||
@ -7177,11 +7173,11 @@ mod solve_expr {
|
||||
F has f : a -> (b -> {}) | a has F, b has G
|
||||
G has g : b -> {} | b has G
|
||||
|
||||
Fo := {}
|
||||
Fo := {} has [F {f}]
|
||||
f = \@Fo {} -> g
|
||||
#^{-1}
|
||||
|
||||
Go := {}
|
||||
Go := {} has [G {g}]
|
||||
g = \@Go {} -> {}
|
||||
#^{-1}
|
||||
|
||||
@ -7225,11 +7221,11 @@ mod solve_expr {
|
||||
F has f : a -> (b -> {}) | a has F, b has G
|
||||
G has g : b -> {} | b has G
|
||||
|
||||
Fo := {}
|
||||
Fo := {} has [F {f}]
|
||||
f = \@Fo {} -> g
|
||||
#^{-1}
|
||||
|
||||
Go := {}
|
||||
Go := {} has [G {g}]
|
||||
g = \@Go {} -> {}
|
||||
#^{-1}
|
||||
|
||||
@ -7260,11 +7256,11 @@ mod solve_expr {
|
||||
F has f : a, b -> ({} -> ({} -> {})) | a has F, b has G
|
||||
G has g : b -> ({} -> {}) | b has G
|
||||
|
||||
Fo := {}
|
||||
Fo := {} has [F {f}]
|
||||
f = \@Fo {}, b -> \{} -> g b
|
||||
#^{-1}
|
||||
|
||||
Go := {}
|
||||
Go := {} has [G {g}]
|
||||
g = \@Go {} -> \{} -> {}
|
||||
#^{-1}
|
||||
|
||||
|
@ -8367,35 +8367,6 @@ All branches in an `if` must have the same type!
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
ability_specialization_with_non_implementing_type,
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [hash] to "./platform"
|
||||
|
||||
Hash has hash : a -> Num.U64 | a has Hash
|
||||
|
||||
hash = \{} -> 0u64
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── ILLEGAL SPECIALIZATION ──────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
This specialization of `hash` is for a non-opaque type:
|
||||
|
||||
5│ hash = \{} -> 0u64
|
||||
^^^^
|
||||
|
||||
It is specialized for
|
||||
|
||||
{}a
|
||||
|
||||
but structural types can never specialize abilities!
|
||||
|
||||
Note: `hash` is a member of `#UserApp.Hash`
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
ability_specialization_does_not_match_type,
|
||||
indoc!(
|
||||
@ -8404,7 +8375,7 @@ All branches in an `if` must have the same type!
|
||||
|
||||
Hash has hash : a -> U64 | a has Hash
|
||||
|
||||
Id := U32
|
||||
Id := U32 has [Hash {hash}]
|
||||
|
||||
hash = \@Id n -> n
|
||||
"#
|
||||
@ -8437,7 +8408,7 @@ All branches in an `if` must have the same type!
|
||||
eq : a, a -> Bool | a has Eq
|
||||
le : a, a -> Bool | a has Eq
|
||||
|
||||
Id := U64
|
||||
Id := U64 has [Eq {eq}]
|
||||
|
||||
eq = \@Id m, @Id n -> m == n
|
||||
"#
|
||||
@ -8456,7 +8427,7 @@ All branches in an `if` must have the same type!
|
||||
);
|
||||
|
||||
test_report!(
|
||||
ability_specialization_overly_generalized,
|
||||
ability_specialization_is_unused,
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [hash] to "./platform"
|
||||
@ -8467,29 +8438,78 @@ All branches in an `if` must have the same type!
|
||||
hash = \_ -> 0u64
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
@r###"
|
||||
── UNUSED DEFINITION ───────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
This specialization of `hash` is overly general:
|
||||
`hash` is not used anywhere in your code.
|
||||
|
||||
6│ hash = \_ -> 0u64
|
||||
^^^^
|
||||
6│ hash = \_ -> 0u64
|
||||
^^^^
|
||||
|
||||
This value is a declared specialization of type:
|
||||
If you didn't intend on using `hash` then remove it so future readers of
|
||||
your code don't wonder why it is there.
|
||||
"###
|
||||
);
|
||||
|
||||
a -> U64
|
||||
test_report!(
|
||||
ability_specialization_is_duplicated,
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [hash, One, Two] to "./platform"
|
||||
|
||||
But the type annotation on `hash` says it must match:
|
||||
Hash has
|
||||
hash : a -> U64 | a has Hash
|
||||
|
||||
a -> U64 | a has Hash
|
||||
One := {} has [Hash {hash}]
|
||||
Two := {} has [Hash {hash}]
|
||||
|
||||
Note: The specialized type is too general, and does not provide a
|
||||
concrete type where a type variable is bound to an ability.
|
||||
hash = \_ -> 0u64
|
||||
"#
|
||||
),
|
||||
// TODO: the error message here could be seriously improved!
|
||||
@r###"
|
||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
Specializations can only be made for concrete types. If you have a
|
||||
generic implementation for this value, perhaps you don't need an
|
||||
ability?
|
||||
"#
|
||||
This specialization of `hash` is overly general:
|
||||
|
||||
9│ hash = \_ -> 0u64
|
||||
^^^^
|
||||
|
||||
This value is a declared specialization of type:
|
||||
|
||||
a -> U64
|
||||
|
||||
But the type annotation on `hash` says it must match:
|
||||
|
||||
a -> U64 | a has Hash
|
||||
|
||||
Note: The specialized type is too general, and does not provide a
|
||||
concrete type where a type variable is bound to an ability.
|
||||
|
||||
Specializations can only be made for concrete types. If you have a
|
||||
generic implementation for this value, perhaps you don't need an
|
||||
ability?
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
#[ignore = "TODO does not error yet"]
|
||||
ability_specialization_is_duplicated_with_type_mismatch,
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [hash, One, Two] to "./platform"
|
||||
|
||||
Hash has
|
||||
hash : a -> U64 | a has Hash
|
||||
|
||||
One := {} has [Hash {hash}]
|
||||
Two := {} has [Hash {hash}]
|
||||
|
||||
hash = \@One _ -> 0u64
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
@ -8501,7 +8521,7 @@ All branches in an `if` must have the same type!
|
||||
Eq has
|
||||
eq : a, a -> Bool | a has Eq
|
||||
|
||||
You := {}
|
||||
You := {} has [Eq {eq}]
|
||||
AndI := {}
|
||||
|
||||
eq = \@You {}, @AndI {} -> False
|
||||
@ -8539,7 +8559,7 @@ All branches in an `if` must have the same type!
|
||||
Hash has
|
||||
hash : a -> U64 | a has Hash
|
||||
|
||||
Id := U64
|
||||
Id := U64 has [Hash {hash}]
|
||||
|
||||
hash : Id -> U32
|
||||
hash = \@Id n -> n
|
||||
@ -8588,7 +8608,7 @@ All branches in an `if` must have the same type!
|
||||
Hash has
|
||||
hash : a -> U64 | a has Hash
|
||||
|
||||
Id := U64
|
||||
Id := U64 has [Hash {hash}]
|
||||
|
||||
hash = \@Id n -> n
|
||||
|
||||
@ -8666,7 +8686,7 @@ All branches in an `if` must have the same type!
|
||||
Hash has
|
||||
hash : a -> U64 | a has Hash
|
||||
|
||||
Id := U64
|
||||
Id := U64 has [Hash {hash}]
|
||||
hash = \@Id n -> n
|
||||
|
||||
hashable : a | a has Hash
|
||||
@ -8879,7 +8899,7 @@ All branches in an `if` must have the same type!
|
||||
Default has default : {} -> a | a has Default
|
||||
|
||||
main =
|
||||
A := {}
|
||||
A := {} has [Default {default}]
|
||||
default = \{} -> @A {}
|
||||
default {}
|
||||
"#
|
||||
@ -9423,40 +9443,6 @@ All branches in an `if` must have the same type!
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
has_encoding_dominated_by_custom,
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" imports [Encode.{ Encoding, toEncoder, custom }] provides [A] to "./platform"
|
||||
|
||||
A := {} has [Encode.Encoding]
|
||||
|
||||
toEncoder = \@A {} -> custom \l, _ -> l
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── CONFLICTING DERIVE AND IMPLEMENTATION ───────────────── /code/proj/Main.roc ─
|
||||
|
||||
`A` both derives and custom-implements `Encode.Encoding`. We found the
|
||||
derive here:
|
||||
|
||||
3│ A := {} has [Encode.Encoding]
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
and one custom implementation of `Encode.Encoding` here:
|
||||
|
||||
5│ toEncoder = \@A {} -> custom \l, _ -> l
|
||||
^^^^^^^^^
|
||||
|
||||
Derived and custom implementations can conflict, so one of them needs
|
||||
to be removed!
|
||||
|
||||
Note: We'll try to compile your program using the custom
|
||||
implementation first, and fall-back on the derived implementation if
|
||||
needed. Make sure to disambiguate which one you want!
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
issue_1755,
|
||||
indoc!(
|
||||
|
Loading…
Reference in New Issue
Block a user