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

Fix #33436 #33445

Conversation

jack-williams
Copy link
Collaborator

@jack-williams jack-williams commented Sep 16, 2019

No description provided.

@jack-williams jack-williams changed the title See what breaks when chaning noConstraintType to unknown See what breaks when changing noConstraintType to unknown Sep 16, 2019
@jack-williams
Copy link
Collaborator Author

All baseline changes are either:

  • rewording of but 'T' could be instantiated with a different subtype of constraint '{}' to use constraint unknown.
  • Additional error elaboration of 'void' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'unknown'. I guess because void is not related to {}, but it is related to unknown.

@AnyhowStep
Copy link
Contributor

AnyhowStep commented Sep 16, 2019

#30637

https://github.com/microsoft/TypeScript/pull/30637/files?file-filters%5B%5D=.ts

The above PR did not modify noConstraintType.

I looked over it quickly but it looks like noConstraintType is some kind of sentinel type?

So, while the constraint is unknown in reality now, the error messages still use the sentinel type and use {} in its output?

And this PR is just updating the sentinel type to match the reality?

Sorry if I sound incoherent =(

@jack-williams
Copy link
Collaborator Author

The error message is a consequence of the fact that noConstraintType is defined as an empty object type, but the error message logic doesn't directly reference noConstraintType, it just looks at the constraint type.

In other words, the error message logic does not look for the sentinel specifically, so it wasn't clear to me whether other code would be the same. I don't know what else uses noConstraintType, or how it uses it, so I wasn't sure if there would be any change in type checking semantics prior to this PR.

The default constraint should be unknown, but it seems there may be a few things that still need tidying up. I'm still not sure whether #32814 is influenced by a legacy implicit constraint.

@jack-williams jack-williams changed the title See what breaks when changing noConstraintType to unknown Change noConstraintType from {} to unknown. Sep 16, 2019
@weswigham
Copy link
Member

Right, noConstraintType is just supposed to be a sentinel (the getConstraintFromTypeParameter and friends functions all check for it to know when to return undefined), but if it is leaking into error messages (or comparisons!?!), changing it is pertinent. The only reason it wasn't changed was because it didn't seem like it needed to be, since "no constraint" isn't actually supposed to be a type.

@weswigham
Copy link
Member

OK, so this error changes because reportRelationError accesses target.immediateBaseConstraint directly - it should then treat an undefined target.immediateBaseConstraint the same as a noConstraintType target.immediateBaseConstraint.

@jack-williams
Copy link
Collaborator Author

So reportRelationError should probably use getBaseConstraint instead?

From a brief look I don't think it is leaking into comparisons, at least judging by the direct accesses to type.immediateBaseConstraint in checker.ts.

Given the churn on baselines, should we leave this until the outcome of #33436 is finalised? I wasn't sure if that was still in discussion.

@weswigham
Copy link
Member

I think #33436 is pretty directly an artifact of not checking for noConstraintType while using type.immediateBaseConstraint directly. I think we should just fix it by checking for the not base constraint type the same way we check for undefined. We can also make the noConstraintType another unknown instead of an object, just in case, but it shouldn't be required, strictly speaking.

So reportRelationError should probably use getBaseConstraint instead?

Yeah, I think so.

@fatcerberus
Copy link

If noConstraintType is just used as a sentinel, does this mean T extends {} will be interpreted as having no constraint?

Then again why do we need a sentinel at all? It seems like if <T> and <T extends unknown> are meant to be equivalent, you could just plug in the unknown upfront and avoid the need for a sentinel value entirely?

@weswigham
Copy link
Member

does this mean T extends {} will be interpreted as having no constraint?

No. That's a T with a constraint of {}.

@fatcerberus
Copy link

Okay then I’m confused. The way you described it before sounded like “no constraint” was being represented internally as T extends noConstraintType and if noConstraintType is currently {}...

@weswigham
Copy link
Member

weswigham commented Sep 18, 2019

noConstraintType is always looked for and replaced with undefined by all callers except this error message (which is the bug), along with the circularConstraintType sentinel.

@fatcerberus
Copy link

No, I get that - my question is, what makes noConstraintType (as it’s currently defined) actually distinguishable from a legit {}? That’s the part I’m hung up on.

@weswigham
Copy link
Member

weswigham commented Sep 18, 2019

It's never supposed to be witnessed as a type. So nothing. It could be a clone of the number 4 - it's just a sentinel value. It happens to be a type (with no defined structure) right now, hence the mistake.

@AnyhowStep
Copy link
Contributor

AnyhowStep commented Sep 18, 2019

So... Better to leave it as {} or change it to a type with a silly name like "you hecked up" (leave the symptom alone), and fix the bug causing the sentinel value to be "witnessed" (deal with the cause)?

Was there a reason to not just use undefined as the sentinel?

Just curious =x

@jack-williams
Copy link
Collaborator Author

Was there a reason to not just use undefined as the sentinel?

Probably to distinguish between types known to have no constraints, and types with lazy constraints not computed yet.

I updated the other sentinels, just because, but I'm happy to revert those changes. Most of the baselines look fine. I marked a couple I'm not sure about.

@jack-williams jack-williams changed the title Change noConstraintType from {} to unknown. Change noConstraintType from {} to unknown and fix #33436 Sep 18, 2019
@weswigham
Copy link
Member

Was there a reason to not just use undefined as the sentinel?

undefined is used for the "has not yet been calculated and cached yet" value. :V

@AnyhowStep
Copy link
Contributor

Why was this closed? o.0

@jack-williams
Copy link
Collaborator Author

I don't think there was an associated issue and I'm just doing my bit to keep the random open PR count down. Can always reopen if there is need!

@AnyhowStep
Copy link
Contributor

Isn't #33436 the associated issue? =x

@jack-williams jack-williams reopened this Nov 18, 2019
@jack-williams jack-williams changed the title Change noConstraintType from {} to unknown and fix #33436 Fix #33436 Nov 18, 2019
@jack-williams
Copy link
Collaborator Author

Yes, you're right.

@@ -1,4 +1,17 @@
tests/cases/compiler/immutable.ts(341,22): error TS2430: Interface 'Keyed<K, V>' incorrectly extends interface 'Collection<K, V>'.
<<<<<<< HEAD
Copy link
Member

Choose a reason for hiding this comment

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

Gotta remove this

}

function f2<A, B extends A>(a: Contravariant<A>, b: Contravariant<B>) {
a = b; // Error
~
!!! error TS2322: Type 'Contravariant<B>' is not assignable to type 'Contravariant<A>'.
!!! error TS2322: Type 'A' is not assignable to type 'B'.
!!! error TS2322: 'A' is assignable to the constraint of type 'B', but 'B' could be instantiated with a different subtype of constraint '{}'.
Copy link
Member

Choose a reason for hiding this comment

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

The previous error message is wrong ({} isn't "interesting" constraint), but shouldn't the user still see an error message here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Presumably the user still sees Type 'A' is not assignable to type 'B'., but I haven't added the elaboration from the linked proposal of:

'B' could be instantiated with an arbitrary type which could be unrelated to 'A'.

@jack-williams
Copy link
Collaborator Author

@DanielRosenwasser Closing this in favor of #35225 as I messed up some merges.

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.

5 participants