Skip to content

Commit

Permalink
generics: fix coercions to distinct phantom types (#848)
Browse files Browse the repository at this point in the history
## Summary

Fix phantom type information being lost in conversions-with-inference
(i.e, `Typ(x)` where `Typ` is a generic type) to distinct types.

## Details

Matching a `B[U]` against a `A[T] = distinct T`, which is what
eventually happens for conversions like `A(B)`, results in the actual
type `B[U]` being matched against the formal type `distinct T`. Since
the invocation information (i.e., `tyGenericInst`) of the actual
type is skipped when the formal type is a `tyDistinct`, phantom type
information present on the instance was lost.

Skipping the invocation information is now removed, and phantom types
are thus passed on properly.
  • Loading branch information
zerbina authored Aug 20, 2023
1 parent 2eed234 commit da8ce86
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 2 deletions.
6 changes: 4 additions & 2 deletions compiler/sem/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1082,7 +1082,7 @@ typeRel can be used to establish various relationships between types:

if a.kind == tyGenericInst and
skipTypes(f, {tyStatic, tyVar, tyLent, tySink}).kind notin {
tyGenericBody, tyGenericInvocation,
tyGenericBody, tyGenericInvocation, tyDistinct,
tyGenericInst, tyGenericParam} + tyTypeClasses:
return typeRel(c, f, lastSon(a), flags)

Expand Down Expand Up @@ -1368,7 +1368,9 @@ typeRel can be used to establish various relationships between types:
inc(c.inheritancePenalty, depth)
result = isSubtype
of tyDistinct:
a = a.skipTypes({tyGenericInst, tyRange})
# FIXME: don't skip ``tyRange`` here. A ``range[D(0) .. D(1)`` is not
# equal to ``D = distinct int``
a = a.skipTypes({tyRange})
if a.kind == tyDistinct:
if sameDistinctTypes(f, a):
result = isEqual
Expand Down
43 changes: 43 additions & 0 deletions tests/typerel/tcoercing_generic_distincts.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
discard """
description: '''
Ensure that types can be coerced into generic distinct types
'''
action: compile
"""

type
Tuple[A] = (int, int) # tuple with phantom type information

Generic[T] = distinct T
Generic2[T] = distinct Tuple[T]

Generic3[T] = distinct Tuple[int]
## generic phantom distinct type of a phantom type

template check(val: untyped, expect: untyped) =
static: doAssert typeof(val) is expect

var x: Tuple[float] = (0, 0)

# coercing a value to an explicitly distinct type works:
check Generic[int](0), Generic[int]
check Generic(int(0)), Generic[int]

# coercing a value that is of phantom type to a distinct type that uses the
# phantom type information works:
check Generic2[float](x), Generic2[float]
check Generic2(x), Generic2[float]

# check that the full instantiated type is bound in the "distinct of generic
# parameter" case
check typeof(Generic(x)).T.A, float

static:
# XXX: issue unrelated to typerel. ``checkConvertible`` skips the relevant
# type information before calling ``cmpTypes``
doAssert compiles(Generic2[int](x)),
"conversion-to-generics start working properly"

# check that different phantom types are not treated as equal in
# to-distinct coercions
doAssert not compiles(Generic3(x))

0 comments on commit da8ce86

Please sign in to comment.