Skip to content

Unsharing pattern types#1909

Merged
trefis merged 3 commits intoocaml:trunkfrom
trefis:unsharing-pattern-types
Jul 26, 2018
Merged

Unsharing pattern types#1909
trefis merged 3 commits intoocaml:trunkfrom
trefis:unsharing-pattern-types

Conversation

@trefis
Copy link
Copy Markdown
Contributor

@trefis trefis commented Jul 16, 2018

Extracts the least controversial part #1675 .

@trefis trefis force-pushed the unsharing-pattern-types branch from 0a2d93b to d7edc97 Compare July 17, 2018 12:06
Copy link
Copy Markdown
Contributor

@garrigue garrigue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Globally, this looks correct. However, I'm wondering what should be returned in pat_type. We seem to have an invariant to keep it non-generic, but wouldn't it make sense to just always put the (generalized) expected_ty, from a semantical point of view?

in
let loc = sp.ppat_loc in
let rup k x =
if constrs = None then (ignore (rp x));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You record the type of the pattern before unification with the expected type.
This is a change w.r.t. the previous behavior.
Is this intentional?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, looking at what does Stypes.record, you are just registering the node earlier, and unification can still occur afterwards. So one has more information if the next unification fails, and the same otherwise. Fine.

begin_def ();
let expected_ty = instance expected_ty in
end_def ();
generalize_structure expected_ty;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it should be OK to use generalize: since we are matching a value, different members could be seen as using independent instances.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it makes a difference here: expected_ty doesn't contain any type variable at the generic level when we receive it. Which means that after the

begin_def;
instance;
end_def;

sequence, there won't be any generalizable variables.

Given that, I'd rather keep the call to generalize_structure here, for uniformity.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. I hadn't seen that due to the generalize_structure in type_cases, there are no generalized type variables in the type.
This would change if switch later to a more agressive policy of taking full instances, that could be fully generalized soundly.

But then it seems that the only improvement of the current patch is to avoid some warnings with label/constructor disambiguation. Is there any other practical change?

generalize_structure expected_ty;
generalize_structure ty_res;
List.iter generalize_structure ty_args;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the sharing of type variables is needed, so this indeed has to be generalize_structure.

@trefis
Copy link
Copy Markdown
Contributor Author

trefis commented Jul 20, 2018

Thanks for the review. I haven't had time to think much about the question you ask (or to fix the small issues in the code) yet, but I'll get back to you some time next week.

@garrigue
Copy link
Copy Markdown
Contributor

I'm copying here an inline comment, as it might no be very visible:

Since, in type_cases, generalize_structure is called before calling type_pattern, expected_ty cannot contain generalized type variables.

As a result, it seems that the only improvement of the current patch is to avoid some warnings with label/constructor disambiguation. Is there any other practical change?

@lpw25
Copy link
Copy Markdown
Contributor

lpw25 commented Jul 25, 2018

I haven't actually tested it with this version of the patch, but I think it should address ambiguity errors like this one:

# type 'a r = { a : 'a; b: 'a };;
type 'a r = { a : 'a; b : 'a; }

# type 'a ty = Int : int ty | Float : float ty;;
type 'a ty = Int : int ty | Float : float ty

# let foo (type a) (ty : a ty) (x : a r) =
    match ty, x with
    | Int, { a = 3; b } -> b
    | _ -> assert false;;

@trefis
Copy link
Copy Markdown
Contributor Author

trefis commented Jul 25, 2018

I haven't actually tested it with this version of the patch, but I think it should address ambiguity errors like this one: [...]

Indeed, that's the test I add with my first commit: at that time it still complains that the type of b is ambiguous, but this is then fixed by the later commits.

As a result, it seems that the only improvement of the current patch is to avoid some warnings with label/constructor disambiguation. Is there any other practical change?

The practical change is illustrated in the test suite by the example Leo just repeated.
As for the principality warnings regarding disambiguation: this PR doesn't contain changes to that effect. I wasn't sure whether we'd completely agreed on that point when we decided to split into smaller PRs. So I went with this small PR first, as it seemed to be the least controversial :)

I plan to open a new PR containing (only) the changes relating to principality warnings as a follow up to this PR.

@trefis
Copy link
Copy Markdown
Contributor Author

trefis commented Jul 25, 2018

However, I'm wondering what should be returned in pat_type. We seem to have an invariant to keep it non-generic, but wouldn't it make sense to just always put the (generalized) expected_ty, from a semantical point of view?

Perhaps. Although I think putting the instance makes just as much sense?
Also, in the implementation, in some cases we don't have a generic type at hand after typing the pattern, which I take as a hint that putting the non-generic type is the right thing to do.

@garrigue
Copy link
Copy Markdown
Contributor

My comment concerning whether pat_type should be generic is also for the future, if we propagate fully generic types: logically this type should be understood as the input of the pattern.

For now I'm satisfied with the current PR, which keeps all invariants, and so is safe.

@trefis trefis force-pushed the unsharing-pattern-types branch from 4a3c5f3 to f658de3 Compare July 25, 2018 12:31
@trefis
Copy link
Copy Markdown
Contributor Author

trefis commented Jul 25, 2018

Understood.

Thanks for looking at this!

I've now rebased and squashed the commits, I'll merge once the CIs are happy (hopefully appveyor won't time out this time).

@trefis trefis force-pushed the unsharing-pattern-types branch from f658de3 to d931b9c Compare July 25, 2018 15:39
@trefis trefis merged commit 9c53eae into ocaml:trunk Jul 26, 2018
@trefis trefis deleted the unsharing-pattern-types branch July 26, 2018 09:01
EmileTrotignon pushed a commit to EmileTrotignon/ocaml that referenced this pull request Jan 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants