Skip to content

Commit a9f1227

Browse files
authoredJan 15, 2020
fix some cases of diagonal subtyping (#34272)
fix #26108, fix #26716, fix #31824
1 parent 15d693b commit a9f1227

File tree

6 files changed

+177
-78
lines changed

6 files changed

+177
-78
lines changed
 

‎NEWS.md

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ New language features
88
Language changes
99
----------------
1010

11+
* Converting arbitrary tuples to `NTuple`, e.g. `convert(NTuple, (1, ""))` now gives an error,
12+
where it used to be incorrectly allowed. This is because `NTuple` refers only to homogeneous
13+
tuples (this meaning has not changed) ([#34272]).
1114

1215
Multi-threading changes
1316
-----------------------

‎base/essentials.jl

+1-3
Original file line numberDiff line numberDiff line change
@@ -333,9 +333,7 @@ convert(T::Type{Tuple{Vararg{V}}}, x::Tuple) where {V} =
333333
#convert(_::Type{Tuple{Vararg{S, N}}},
334334
# x::Tuple{Vararg{Any, N}}) where
335335
# {S, N} = cnvt_all(S, x...)
336-
# TODO: These currently can't be used since
337-
# Type{NTuple} <: (Type{Tuple{Vararg{S}}} where S) is true
338-
# even though the value S doesn't exist
336+
# TODO: These are similar to the methods we currently use but cnvt_all might work better:
339337
#convert(_::Type{Tuple{Vararg{S}}},
340338
# x::Tuple{Any, Vararg{Any}}) where
341339
# {S} = cnvt_all(S, x...)

‎doc/src/devdocs/types.md

+26-5
Original file line numberDiff line numberDiff line change
@@ -403,17 +403,38 @@ f(nothing, 2.0)
403403
These examples are telling us something: when `x` is `nothing::Nothing`, there are no
404404
extra constraints on `y`.
405405
It is as if the method signature had `y::Any`.
406-
This means that whether a variable is diagonal is not a static property based on
407-
where it appears in a type.
408-
Rather, it depends on where a variable appears when the subtyping algorithm *uses* it.
409-
When `x` has type `Nothing`, we don't need to use the `T` in `Union{Nothing,T}`, so `T`
410-
does not "occur".
411406
Indeed, we have the following type equivalence:
412407

413408
```julia
414409
(Tuple{Union{Nothing,T},T} where T) == Union{Tuple{Nothing,Any}, Tuple{T,T} where T}
415410
```
416411

412+
The general rule is: a concrete variable in covariant position acts like it's
413+
not concrete if the subtyping algorithm only *uses* it once.
414+
When `x` has type `Nothing`, we don't need to use the `T` in `Union{Nothing,T}`;
415+
we only use it in the second slot.
416+
This arises naturally from the observation that in `Tuple{T} where T` restricting
417+
`T` to concrete types makes no difference; the type is equal to `Tuple{Any}` either way.
418+
419+
However, appearing in *invariant* position disqualifies a variable from being concrete
420+
whether that appearance of the variable is used or not.
421+
Otherwise types can behave differently depending on which other types
422+
they are compared to, making subtyping not transitive. For example, consider
423+
424+
Tuple{Int,Int8,Vector{Integer}} <: Tuple{T,T,Vector{Union{Integer,T}}} where T
425+
426+
If the `T` inside the Union is ignored, then `T` is concrete and the answer is "false"
427+
since the first two types aren't the same.
428+
But consider instead
429+
430+
Tuple{Int,Int8,Vector{Any}} <: Tuple{T,T,Vector{Union{Integer,T}}} where T
431+
432+
Now we cannot ignore the `T` in the Union (we must have T == Any), so `T` is not
433+
concrete and the answer is "true".
434+
That would make the concreteness of `T` depend on the other type, which is not
435+
acceptable since a type must have a clear meaning on its own.
436+
Therefore the appearance of `T` inside `Vector` is considered in both cases.
437+
417438
## Subtyping diagonal variables
418439

419440
The subtyping algorithm for diagonal variables has two components:

0 commit comments

Comments
 (0)
Please sign in to comment.