Syntactic ability links in solve

This commit is contained in:
Ayaz Hafiz 2022-07-18 18:33:28 -04:00
parent 4d0c1e6a9c
commit d2da395619
No known key found for this signature in database
GPG Key ID: 0E2A37416A25EF58
5 changed files with 115 additions and 130 deletions

View File

@ -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 {}

View File

@ -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 {

View File

@ -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));

View File

@ -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}

View File

@ -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!(