Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restrict usages of type variables in non-generalized contexts #7454

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ ROC_TRACE_COMPACTION = "0"
ROC_PRINT_UNIFICATIONS_DERIVED = "0"
ROC_PRINT_MISMATCHES = "0"
ROC_PRINT_FIXPOINT_FIXING = "0"
ROC_VERIFY_RIGID_LET_GENERALIZED = "0"
ROC_VERIFY_OCCURS_ONE_RECURSION = "0"
ROC_CHECK_MONO_IR = "0"
ROC_PRINT_IR_AFTER_SPECIALIZATION = "0"
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/cli/tests/benchmarks/AStar.roc
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ astar = \cost_fn, move_fn, goal, model ->
new_neighbors =
Set.difference(neighbors, model_popped.evaluated)

model_with_neighbors : Model position
model_with_neighbors : Model _
model_with_neighbors =
model_popped
|> &open_set(Set.union(model_popped.open_set, new_neighbors))

walker : Model position, position -> Model position
walker : Model _, _ -> Model _
walker = \amodel, n -> update_cost(current, n, amodel)

model_with_costs =
Expand Down
2 changes: 1 addition & 1 deletion crates/compiler/builtins/roc/Num.roc
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ pi = 3.14159265358979323846264338327950288419716939937510

## Circle constant (τ)
tau : Frac *
tau = 2 * pi
tau = 6.2831853071795864769252867665590057683943387987502

# ------- Functions
## Convert a number to a [Str].
Expand Down
2 changes: 1 addition & 1 deletion crates/compiler/can/src/constraint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,7 @@ pub struct DefTypes {
pub loc_symbols: Slice<(Symbol, Region)>,
}

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Generalizable(pub bool);

#[derive(Debug, Clone)]
Expand Down
16 changes: 0 additions & 16 deletions crates/compiler/debug_flags/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,22 +95,6 @@ flags! {
/// Prints all type variables entered for fixpoint-fixing.
ROC_PRINT_FIXPOINT_FIXING

/// Verifies that after let-generalization of a def, any rigid variables in the type annotation
/// of the def are indeed generalized.
///
/// Note that rigids need not always be generalized in a def. For example, they may be
/// constrained by a type from a lower rank, as `b` is in the following def:
///
/// F a : { foo : a }
/// foo = \arg ->
/// x : F b
/// x = arg
/// x.foo
///
/// Instead, this flag is useful for checking that in general, introduction is correct, when
/// chainging how defs are constrained.
ROC_VERIFY_RIGID_LET_GENERALIZED

/// Verifies that an `occurs` check indeed only contains non-recursive types that need to be
/// fixed-up with one new recursion variable.
///
Expand Down
148 changes: 103 additions & 45 deletions crates/compiler/load/tests/test_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1522,18 +1522,18 @@ mod test_reporting {
from_annotation_if,
indoc!(
r"
x : Num.Int *
x : Num.Int _
x = if Bool.true then 3.14 else 4

x
"
),
@r"
@r###"
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────

Something is off with the `then` branch of this `if` expression:

4│ x : Num.Int *
4│ x : Num.Int _
5│ x = if Bool.true then 3.14 else 4
^^^^

Expand All @@ -1547,27 +1547,27 @@ mod test_reporting {

Tip: You can convert between integers and fractions using functions
like `Num.to_frac` and `Num.round`.
"
"###
);

test_report!(
from_annotation_when,
indoc!(
r"
x : Num.Int *
x : Num.Int _
x =
when True is
_ -> 3.14

x
"
),
@r"
@r###"
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────

Something is off with the body of the `x` definition:

4│ x : Num.Int *
4│ x : Num.Int _
5│ x =
6│> when True is
7│> _ -> 3.14
Expand All @@ -1582,7 +1582,7 @@ mod test_reporting {

Tip: You can convert between integers and fractions using functions
like `Num.to_frac` and `Num.round`.
"
"###
);

test_report!(
Expand Down Expand Up @@ -1910,7 +1910,7 @@ mod test_reporting {
from_annotation_complex_pattern,
indoc!(
r"
{ x } : { x : Num.Int * }
{ x } : { x : Num.Int _ }
{ x } = { x: 4.0 }

x
Expand All @@ -1921,7 +1921,7 @@ mod test_reporting {

Something is off with the body of this definition:

4│ { x } : { x : Num.Int * }
4│ { x } : { x : Num.Int _ }
5│ { x } = { x: 4.0 }
^^^^^^^^^^

Expand Down Expand Up @@ -2047,18 +2047,18 @@ mod test_reporting {
missing_fields,
indoc!(
r"
x : { a : Num.Int *, b : Num.Frac *, c : Str }
x : { a : Num.Int _, b : Num.Frac _, c : Str }
x = { b: 4.0 }

x
"
),
@r"
@r###"
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────

Something is off with the body of the `x` definition:

4│ x : { a : Num.Int *, b : Num.Frac *, c : Str }
4│ x : { a : Num.Int _, b : Num.Frac _, c : Str }
5│ x = { b: 4.0 }
^^^^^^^^^^

Expand All @@ -2075,7 +2075,7 @@ mod test_reporting {
}

Tip: Looks like the c and a fields are missing.
"
"###
);

// this previously reported the message below, not sure which is better
Expand Down Expand Up @@ -3448,7 +3448,7 @@ mod test_reporting {
x : AList Num.I64 Num.I64
x = ACons 0 (BCons 1 (ACons "foo" BNil ))

y : BList a a
y : BList _ _
y = BNil

{ x, y }
Expand Down Expand Up @@ -4189,9 +4189,8 @@ mod test_reporting {
RBTree k v : [Node NodeColor k v (RBTree k v) (RBTree k v), Empty]

# Create an empty dictionary.
empty : RBTree k v
empty =
Empty
empty : {} -> RBTree k v
empty = \{} -> Empty

empty
"
Expand Down Expand Up @@ -11215,10 +11214,10 @@ All branches in an `if` must have the same type!

import Decode exposing [decoder]

main =
my_decoder : Decoder (a -> a) fmt where fmt implements DecoderFormatting
my_decoder = decoder
my_decoder : Decoder (_ -> _) _
my_decoder = decoder

main =
my_decoder
"#
),
Expand All @@ -11227,12 +11226,12 @@ All branches in an `if` must have the same type!

This expression has a type that does not implement the abilities it's expected to:

7│ my_decoder = decoder
^^^^^^^
6│ my_decoder = decoder
^^^^^^^

I can't generate an implementation of the `Decoding` ability for

a -> a
* -> *

Note: `Decoding` cannot be generated for functions.
"
Expand All @@ -11248,10 +11247,10 @@ All branches in an `if` must have the same type!

A := {}

main =
my_decoder : Decoder {x : A} fmt where fmt implements DecoderFormatting
my_decoder = decoder
my_decoder : Decoder {x : A} _
my_decoder = decoder

main =
my_decoder
"#
),
Expand All @@ -11260,8 +11259,8 @@ All branches in an `if` must have the same type!

This expression has a type that does not implement the abilities it's expected to:

9│ my_decoder = decoder
^^^^^^^
8│ my_decoder = decoder
^^^^^^^

I can't generate an implementation of the `Decoding` ability for

Expand Down Expand Up @@ -11511,20 +11510,19 @@ All branches in an `if` must have the same type!

import Decode exposing [decoder]

main =
my_decoder : Decoder {x : Str, y ? Str} fmt where fmt implements DecoderFormatting
my_decoder = decoder
my_decoder : Decoder {x : Str, y ? Str} _
my_decoder = decoder

my_decoder
main = my_decoder
"#
),
@r"
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────

This expression has a type that does not implement the abilities it's expected to:

7│ my_decoder = decoder
^^^^^^^
6│ my_decoder = decoder
^^^^^^^

I can't generate an implementation of the `Decoding` ability for

Expand Down Expand Up @@ -14108,11 +14106,10 @@ All branches in an `if` must have the same type!

import Decode exposing [decoder]

main =
my_decoder : Decoder (U32, Str) fmt where fmt implements DecoderFormatting
my_decoder = decoder
my_decoder : Decoder (U32, Str) _
my_decoder = decoder

my_decoder
main = my_decoder
"#
)
);
Expand All @@ -14125,20 +14122,19 @@ All branches in an `if` must have the same type!

import Decode exposing [decoder]

main =
my_decoder : Decoder (U32, {} -> {}) fmt where fmt implements DecoderFormatting
my_decoder = decoder
my_decoder : Decoder (U32, {} -> {}) _
my_decoder = decoder

my_decoder
main = my_decoder
"#
),
@r"
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────

This expression has a type that does not implement the abilities it's expected to:

7│ my_decoder = decoder
^^^^^^^
6│ my_decoder = decoder
^^^^^^^

I can't generate an implementation of the `Decoding` ability for

Expand Down Expand Up @@ -15994,4 +15990,66 @@ All branches in an `if` must have the same type!
Str -> {}
"#
);

test_report!(
invalid_generic_literal,
indoc!(
r#"
module [v]

v : *
v = 1
"#
),
@r###"
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────

Something is off with the body of the `v` definition:

3│ v : *
4│ v = 1
^

The body is a number of type:

Num *

But the type annotation on `v` says it should be:

*

Tip: The type annotation uses the type variable `*` to say that this
definition can produce any type of value. But in the body I see that
it will only produce a `Num` value of a single specific type. Maybe
change the type annotation to be more specific? Maybe change the code
to be more general?
"###
);

test_report!(
invalid_generic_literal_list,
indoc!(
r#"
module [v]

v : List *
v = []
"#
),
@r###"
── TYPE VARIABLE IS NOT GENERIC in /code/proj/Main.roc ─────────────────────────

This type variable has a single type:

3│ v : List *
^

Type variables tell me that they can be used with any type, but they
can only be used with functions. All other values have exactly one
type.

Hint: If you would like the type to be inferred for you, use an
underscore _ instead.
"###
);
}
Loading
Loading