Skip to content

Add the comparability relationship to the spec #17215

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

Closed
wants to merge 2 commits into from

Conversation

DanielRosenwasser
Copy link
Member

It's been a while since we've updated the spec, so this is me taking my first swing at it. I'm batching up updates in the specUpdate branch, and will commit/merge the final docx and pdf files when it's ready. @ahejlsberg, I'd like to get some feedback on here or offline given these changes.

My first update is the comparability relationship since that's something I have a lot of background on. Eventually, I'd like to branch into other more involved topics.

Fixes #17214.

@olegdunkan
Copy link

@DanielRosenwasser

type A = string | number | boolean;
type B = string;

var a:A;
var b:B;

a=b;
b=a; //it was error in 1.8.0

It was an error at the last line of snippet in 1.8 version, but now it is not. Is it effect of CFA or something else? I don't think that it is a bug but I think the spec lacks of description of that. Quick info shows us that the type of a are changed from A in a = b to string in b = a.

@DanielRosenwasser
Copy link
Member Author

@olegdunkan this isn't really related to comparability; we still use assignability in assignments. Like you said, it's a result of control flow analyzed types, as we also use the narrowed type of a at that location. That's currently not described in the spec.

@olegdunkan
Copy link

olegdunkan commented Jul 21, 2017

this isn't really related to comparability;

Yes, I understand
I wrote this in the issue because it is the alone issue related to changes of the spec. I didn't want to create a new issue. Sorry for that.

@DanielRosenwasser
Copy link
Member Author

This needs to update sections like union types as well.


*TODO: Document the base primitive type.

*Types are required to be *comparable* in certain circumstances, such as part of when checking whether two values of given types might be equal at runtime using operators like '===', or when using a type assertion.
Copy link
Member

Choose a reason for hiding this comment

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

We should mention how this definition is really similar to assignment compatibility, and even probably provide it first as a diff, or maybe afterward as a diff.

Copy link
Member

Choose a reason for hiding this comment

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

Never mind, I found it below.

* *S* and *T* are identical types.
* *S* or *T* is the Any type.
* *S* or *T* is an enum type and the other is the primitive type Number.
* *S* is a literal type and *T* is the base primitive type of S.
Copy link
Member

Choose a reason for hiding this comment

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

do the new rules for literal types apply here? I need to double-check.


When comparing call or construct signatures, parameter names are ignored and rest parameters correspond to an unbounded expansion of optional parameters of the rest parameter element type.

Note that specialized call and construct signatures (section [3.9.2.4](#3.9.2.4)) are not significant when determining assignment compatibility.
Copy link
Member

Choose a reason for hiding this comment

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

Specialized signatures are not a thing anymore, I think. Though we should check whether the rules for validating overload sets are up to date.

Copy link
Member Author

Choose a reason for hiding this comment

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

Comparability

*S* is ***comparable to*** a type *T*, and *T* is ***comparable from*** *S*, if one of the following is true:

* *S* and *T* are identical types.
* *S* or *T* is the Any type.
Copy link
Member

Choose a reason for hiding this comment

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

simpleTypeRelatedTo rules go here, overwriting lines 2367-2369. (Note that simpleTypeRelatedTo is called twice, but I flatten the rules so we don't have to say "only this part is symmetric".)

  • S is the never type.
  • S is a literal type and T is the base primitive type of S. (note: and vice versa for comparability)
  • S is an enum member with a literal type and T is a literal type that is not an enum member, and the literal values of S and T are the same. (note: and vice versa, for comparability)
  • S and T are enum members and come from the same enum.
  • S and T are enum members with a literal type and the literal values of S and T are the same, and S and T come from the same enum.
  • S and T are the undefined or void types. (note: for assignability, the rule is "S is the undefined type and T is the undefined or void types.")
  • S and T are the null type.
  • S or T is an object type and the other is the object type. (note: assignability is "S is an object type and T is the object type.")
  • S or T is an enum type and the other is the number type or a numeric literal type that is not the type of an enum member.

Copy link
Member Author

Choose a reason for hiding this comment

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

We need a section that describes how enums "come from the same enum" - because we really need an enum relation section.

Copy link
Member

Choose a reason for hiding this comment

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

Also "S and T are enum types and come from the same enum" instead of "S and T are enum members ...".

* *S* or *T* is the Any type.
* *S* or *T* is an enum type and the other is the primitive type Number.
* *S* is a literal type and *T* is the base primitive type of S.
* *S* is a union type and some constituent type of *S* is comparable to *T*.
Copy link
Member

Choose a reason for hiding this comment

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

TODO: Excess property check goes above this line.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't believe that's relevant to comparability.

* *S* is an intersection type and at least one constituent type of *S* is comparable to *T*.
* *T* is a union type and *S* is comparable to at least one constituent type of *T*.
* *T* is an intersection type and *S* is comparable to each constituent type of *T*.
* *S* is a type parameter and the constraint of *S* is comparable to *T*.
Copy link
Member

Choose a reason for hiding this comment

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

Above this line:

  • T is a type parameter and S is mapped type { [P in keyof T]: X } and X is related to T[P].
  • T is a keyof type keyof T' and
    • S is a keyof type keyof S' and T' is comparable to S', or
    • S is related to keyof C, where C is the constraint of T'.
  • T is an indexed access type T'[K] and S is related to C[K], where C is the constraint of T'.
  • S is a mapped type { [P in keyof S]: X } and S[P] is related to X.

Copy link
Member

Choose a reason for hiding this comment

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

On this line, append "and T is not the object type."

Copy link
Member

@sandersn sandersn Dec 4, 2017

Choose a reason for hiding this comment

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

Below this line:

  • S is an indexed access type S'[K] and C[K] is related to T, where C is the constraint of S'.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure what some of these corrections refer to, but should

  • S is a mapped type { [P in keyof S]: X } and S[P] is related to X.

be

  • T is a mapped type { [P in K]: X }, S is not a mapped type, keyof S is identical to K, and S[K] is comparable to X.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, looks like I just messed that one up. It should be "S[P] is comparable to X", though. You could write it more compactly as:

  • T is a mapped type { [P in keyof S]: X } and S[P] is comparable to X, where S is not a mapped type.

Since you can express the identity of K and keyof S implicitly.

* *M* is a non-specialized call or construct signature and *S* has an apparent call or construct signature *N* where, when *M* and *N* are instantiated using type Any as the type argument for all type parameters declared by *M* and *N* (if any),
* the signatures are of the same kind (call or construct),
* *M* has a rest parameter or the number of non-optional parameters in *N* is less than or equal to the total number of parameters in *M*,
* for parameter positions that are present in both signatures, each parameter type in *N* is comparable to or from the corresponding parameter type in *M*, and
Copy link
Member

Choose a reason for hiding this comment

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

TODO: Doesn't cover this-parameters.
TODO: Doesn't cover relatability of spreads to non-spread parameters.
TODO: Doesn't cover stricter variance checks.

We can probably merge without these, but I'll take a look at them next.

Copy link
Member

Choose a reason for hiding this comment

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

  • if M has a this-parameter whose type is not the void type, then it must be comparable to the this-parameter type of N or N must not have a this-parameter.

Copy link
Member Author

Choose a reason for hiding this comment

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

@mhegazy mhegazy added the Spec Issues related to the TypeScript language specification label Jan 5, 2018
@mhegazy
Copy link
Contributor

mhegazy commented Mar 29, 2018

@DanielRosenwasser can we get these in?

@RyanCavanaugh
Copy link
Member

Closing in favor of #20686

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Spec Issues related to the TypeScript language specification
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants