Skip to content

Commit 7aa786a

Browse files
committed
partial fix for #273
1 parent a30a672 commit 7aa786a

23 files changed

+139
-135
lines changed

Sources/Signatures/Generics/GenericConstraint.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,8 @@ extension GenericConstraint:Sendable where Scalar:Sendable
3535
extension GenericConstraint
3636
{
3737
@inlinable public
38-
func map<T>(_ transform:(Scalar) throws -> T) rethrows -> GenericConstraint<T>
38+
func map<T>(_ transform:(Scalar) throws -> T?) rethrows -> GenericConstraint<T>
3939
{
4040
.where(self.noun, is: self.what, to: try self.whom.map(transform))
4141
}
42-
@inlinable public
43-
func flatMap<T>(_ transform:(Scalar) throws -> T?) rethrows -> GenericConstraint<T>?
44-
{
45-
try self.whom.flatMap(transform).map { .where(self.noun, is: self.what, to: $0) }
46-
}
4742
}
Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
@frozen public
2-
enum GenericType<Scalar>
2+
struct GenericType<Scalar>
33
{
4-
case nominal(Scalar)
5-
case complex(String)
4+
public
5+
let spelling:String
6+
public
7+
let nominal:Scalar?
8+
9+
@inlinable public
10+
init(spelling:String, nominal:Scalar? = nil)
11+
{
12+
self.spelling = spelling
13+
self.nominal = nominal
14+
}
615
}
716
extension GenericType:Equatable where Scalar:Equatable
817
{
@@ -15,34 +24,23 @@ extension GenericType:Sendable where Scalar:Sendable
1524
}
1625
extension GenericType:Comparable where Scalar:Comparable
1726
{
18-
}
19-
extension GenericType
20-
{
21-
@inlinable public
22-
var nominal:Scalar?
23-
{
24-
switch self
25-
{
26-
case .nominal(let type): type
27-
case .complex: nil
28-
}
29-
}
3027
@inlinable public
31-
func map<T>(_ transform:(Scalar) throws -> T) rethrows -> GenericType<T>
28+
static func < (a:Self, b:Self) -> Bool
3229
{
33-
switch self
30+
switch (a.nominal, b.nominal)
3431
{
35-
case .nominal(let type): .nominal(try transform(type))
36-
case .complex(let type): .complex(type)
32+
case (let i?, let j?): (i, a.spelling) < (j, b.spelling)
33+
case (_?, nil): true
34+
case (nil, _?): false
35+
case (nil, nil): a.spelling < b.spelling
3736
}
3837
}
38+
}
39+
extension GenericType
40+
{
3941
@inlinable public
40-
func flatMap<T>(_ transform:(Scalar) throws -> T?) rethrows -> GenericType<T>?
42+
func map<T>(_ transform:(Scalar) throws -> T?) rethrows -> GenericType<T>
4143
{
42-
switch self
43-
{
44-
case .nominal(let type): try transform(type).map { .nominal($0) }
45-
case .complex(let type): .complex(type)
46-
}
44+
.init(spelling: self.spelling, nominal: try self.nominal.map(transform) ?? nil)
4745
}
4846
}

Sources/SymbolGraphParts/Generics/GenericConstraint (ext).swift

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,9 @@ extension GenericConstraint:JSONObjectDecodable, JSONDecodable where Scalar:JSON
1414
public
1515
init(json:JSON.ObjectDecoder<CodingKey>) throws
1616
{
17-
let type:GenericType<Scalar>
18-
if let scalar:Scalar = try json[.rhsPrecise]?.decode()
19-
{
20-
type = .nominal(scalar)
21-
}
22-
else
23-
{
24-
type = .complex(try json[.rhs].decode())
25-
}
26-
2717
self = .where(try json[.lhs].decode(),
2818
is: try json[.kind].decode(as: Kind.self, with: \.operator),
29-
to: type)
19+
to: .init(spelling: try json[.rhs].decode(),
20+
nominal: try json[.rhsPrecise]?.decode()))
3021
}
3122
}

Sources/SymbolGraphTests/Main.Generics.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ extension Main.Generics:TestBattery
3737
{
3838
for (name, whom):(String, GenericType<Int32>) in
3939
[
40-
("nominal", .nominal(13)),
41-
("complex", .complex("Dictionary<Int, String>.Index"))
40+
("nominal", .init(spelling: "", nominal: 13)),
41+
("complex", .init(spelling: "Dictionary<Int, String>.Index", nominal: nil))
4242
]
4343
{
4444
guard let tests:TestGroup = tests / name

Sources/SymbolGraphs/Generics/GenericConstraint (ext).swift

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@ extension GenericConstraint
88
///
99
/// The BSON coding schema looks roughly like one of
1010
///
11-
/// `{ G: "0GenericParameterName.AssociatedType", N: 0x1234_5678 }`
11+
/// `{ G: "0GenericParameterName.AssociatedType", C: "Int", N: 0x1234_5678 }`
1212
///
1313
/// or
1414
///
1515
/// `{ G: "0GenericParameterName.AssociatedType", C: "Array<Int>" }` .
1616
///
17-
/// The nominal (`N`) field is usually integer-typed, but its BSON
17+
/// The ``nominal`` (`N`) field is usually integer-typed, but its BSON
1818
/// representation is up to the generic ``Scalar`` parameter.
1919
///
20-
/// The complex (`C`) field is always a string.
20+
/// The ``spelling`` (`C`) field is always a string.
21+
///
22+
/// Prior to 0.9.9, the ``spelling`` was optional.
2123
@frozen public
2224
enum CodingKey:String, Sendable
2325
{
2426
case generic = "G"
2527
case nominal = "N"
26-
case complex = "C"
28+
case spelling = "C"
29+
30+
@available(*, deprecated, renamed: "spelling")
31+
static var complex:Self { .spelling }
2732
}
2833
}
2934
extension GenericConstraint:BSONDocumentEncodable, BSONEncodable
@@ -41,12 +46,9 @@ extension GenericConstraint:BSONDocumentEncodable, BSONEncodable
4146
}
4247

4348
bson[.generic] = "\(sigil)\(self.noun)"
44-
45-
switch self.whom
46-
{
47-
case .nominal(let type): bson[.nominal] = type
48-
case .complex(let description): bson[.complex] = description
49-
}
49+
bson[.nominal] = self.whom.nominal
50+
// For roundtripping pre-0.9.9 BSON. After 1.0, we should encode it unconditionally.
51+
bson[.spelling] = self.whom.spelling.isEmpty ? nil : self.whom.spelling
5052
}
5153
}
5254
extension GenericConstraint:BSONDocumentDecodable, BSONDecodable
@@ -72,19 +74,10 @@ extension GenericConstraint:BSONDocumentDecodable, BSONDecodable
7274
return (sigil, .init(decoding: $0.bytes.dropFirst(), as: Unicode.UTF8.self))
7375
}
7476

75-
let type:GenericType<Scalar>
76-
// If there is a null value (which is allowed if `Scalar` is an ``Optional`` type),
77-
// we don’t want to attempt to decode from ``CodingKey.complex``. If we do not
78-
// specify the decoded type (`Scalar.self`), the compiler will infer it to be
79-
// `Scalar?`, which will cause us to fall through to the else block!
80-
if let scalar:Scalar = try bson[.nominal]?.decode(to: Scalar.self)
81-
{
82-
type = .nominal(scalar)
83-
}
84-
else
85-
{
86-
type = .complex(try bson[.complex].decode())
87-
}
77+
let type:GenericType<Scalar> = .init(
78+
// TODO: deoptionalize this after 1.0.
79+
spelling: try bson[.spelling]?.decode() ?? "",
80+
nominal: try bson[.nominal]?.decode())
8881

8982
switch sigil
9083
{

Sources/SymbolGraphs/SymbolGraphABI.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ import SemanticVersions
33
@frozen public
44
enum SymbolGraphABI
55
{
6-
@inlinable public static var version:PatchVersion { .v(0, 9, 8) }
6+
@inlinable public static var version:PatchVersion { .v(0, 9, 9) }
77
}

Sources/UnidocLinker/Sema/ConstraintReductionError.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import SourceDiagnostics
44

55
struct ConstraintReductionError:Error, Equatable, Sendable
66
{
7-
let constraints:[[GenericConstraint<Unidoc.Scalar?>]]
8-
let minimal:[GenericConstraint<Unidoc.Scalar?>]
7+
let constraints:[[GenericConstraint<Unidoc.Scalar>]]
8+
let minimal:[GenericConstraint<Unidoc.Scalar>]
99
let subject:Unidoc.Scalar
1010
let `protocol`:Unidoc.Scalar
1111

12-
init(invalid constraints:[[GenericConstraint<Unidoc.Scalar?>]],
13-
minimal:[GenericConstraint<Unidoc.Scalar?>],
12+
init(invalid constraints:[[GenericConstraint<Unidoc.Scalar>]],
13+
minimal:[GenericConstraint<Unidoc.Scalar>],
1414
subject:Unidoc.Scalar,
1515
`protocol`:Unidoc.Scalar)
1616
{

Sources/UnidocLinker/Sema/Unidoc.Conformers.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ extension Unidoc.Conformers
2424
{
2525
mutating
2626
func append(conformer type:Unidoc.Scalar,
27-
where constraints:[GenericConstraint<Unidoc.Scalar?>])
27+
where constraints:[GenericConstraint<Unidoc.Scalar>])
2828
{
2929
constraints.isEmpty
3030
? self.unconditional.append(type)

Sources/UnidocLinker/Sema/Unidoc.ExtensionConditions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ extension Unidoc
55
{
66
struct ExtensionConditions:Equatable, Hashable, Sendable
77
{
8-
var constraints:[GenericConstraint<Unidoc.Scalar?>]
8+
var constraints:[GenericConstraint<Unidoc.Scalar>]
99
let culture:Int
1010

11-
init(constraints:[GenericConstraint<Unidoc.Scalar?>], culture:Int)
11+
init(constraints:[GenericConstraint<Unidoc.Scalar>], culture:Int)
1212
{
1313
self.constraints = constraints
1414
self.culture = culture

Sources/UnidocLinker/Sema/Unidoc.Linker.Table.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ extension Unidoc.Linker.Table<Unidoc.Extension>
127127
return [:]
128128
}
129129

130-
let universal:Set<GenericConstraint<Unidoc.Scalar?>> =
130+
let universal:Set<GenericConstraint<Unidoc.Scalar>> =
131131
extendedDecl.signature.generics.constraints.reduce(into: [])
132132
{
133133
$0.insert($1.map { extendedSnapshot.scalars.decls[$0] })
@@ -139,7 +139,7 @@ extension Unidoc.Linker.Table<Unidoc.Extension>
139139
.init(
140140
constraints: $0.conditions.compactMap
141141
{
142-
let constraint:GenericConstraint<Unidoc.Scalar?> = $0.map
142+
let constraint:GenericConstraint<Unidoc.Scalar> = $0.map
143143
{
144144
context.current.scalars.decls[$0]
145145
}
@@ -174,7 +174,15 @@ extension Unidoc.Linker.Table<Unidoc.Extension>
174174
/// ``RawRepresentable`` in the standard library.
175175
conditions.constraints.removeAll
176176
{
177-
$0 == .where("Self", is: .conformer, to: .nominal(s))
177+
if case .where("Self", is: .conformer, to: let type) = $0,
178+
case s? = type.nominal
179+
{
180+
true
181+
}
182+
else
183+
{
184+
false
185+
}
178186
}
179187
}
180188
// It’s possible for two locally-disjoint extensions to coalesce

0 commit comments

Comments
 (0)