From 7aa786a0346e5dc52d62a3f42fe97f9550d74c87 Mon Sep 17 00:00:00 2001 From: taylorswift Date: Tue, 16 Jul 2024 23:41:23 +0000 Subject: [PATCH 1/2] partial fix for #273 --- .../Generics/GenericConstraint.swift | 7 +-- Sources/Signatures/Generics/GenericType.swift | 48 +++++++++---------- .../Generics/GenericConstraint (ext).swift | 13 +---- Sources/SymbolGraphTests/Main.Generics.swift | 4 +- .../Generics/GenericConstraint (ext).swift | 39 +++++++-------- Sources/SymbolGraphs/SymbolGraphABI.swift | 2 +- .../Sema/ConstraintReductionError.swift | 8 ++-- .../UnidocLinker/Sema/Unidoc.Conformers.swift | 2 +- .../Sema/Unidoc.ExtensionConditions.swift | 4 +- .../Sema/Unidoc.Linker.Table.swift | 14 ++++-- Sources/UnidocLinker/Unidoc.Linker.swift | 33 ++++++++----- .../UnidocLinker/Unidoc.Symbolicator.swift | 45 +++++++++-------- .../Volumes/Mongo.Variable (ext).swift | 4 +- .../Unidoc.LookupAdjacent.Vertices.swift | 2 +- Sources/UnidocRecords/Unidoc.EditionSet.swift | 6 +-- .../Groups/Unidoc.ConformingType.swift | 4 +- .../Groups/Unidoc.ExtensionGroup.swift | 4 +- .../Cones/Unidoc.Cone.Halo.Generics.swift | 4 +- Sources/UnidocUI/Cones/Unidoc.Cone.Halo.swift | 2 +- .../Sections/Unidoc.DenseList.Card.swift | 2 +- .../Sections/Unidoc.ExtensionSection.swift | 2 +- .../Sections/Unidoc.WhereClause.swift | 4 +- Sources/UnidocUI/operators.swift | 21 ++++---- 23 files changed, 139 insertions(+), 135 deletions(-) diff --git a/Sources/Signatures/Generics/GenericConstraint.swift b/Sources/Signatures/Generics/GenericConstraint.swift index f25e69919..ca79f75be 100644 --- a/Sources/Signatures/Generics/GenericConstraint.swift +++ b/Sources/Signatures/Generics/GenericConstraint.swift @@ -35,13 +35,8 @@ extension GenericConstraint:Sendable where Scalar:Sendable extension GenericConstraint { @inlinable public - func map(_ transform:(Scalar) throws -> T) rethrows -> GenericConstraint + func map(_ transform:(Scalar) throws -> T?) rethrows -> GenericConstraint { .where(self.noun, is: self.what, to: try self.whom.map(transform)) } - @inlinable public - func flatMap(_ transform:(Scalar) throws -> T?) rethrows -> GenericConstraint? - { - try self.whom.flatMap(transform).map { .where(self.noun, is: self.what, to: $0) } - } } diff --git a/Sources/Signatures/Generics/GenericType.swift b/Sources/Signatures/Generics/GenericType.swift index d016609d6..870105c14 100644 --- a/Sources/Signatures/Generics/GenericType.swift +++ b/Sources/Signatures/Generics/GenericType.swift @@ -1,8 +1,17 @@ @frozen public -enum GenericType +struct GenericType { - case nominal(Scalar) - case complex(String) + public + let spelling:String + public + let nominal:Scalar? + + @inlinable public + init(spelling:String, nominal:Scalar? = nil) + { + self.spelling = spelling + self.nominal = nominal + } } extension GenericType:Equatable where Scalar:Equatable { @@ -15,34 +24,23 @@ extension GenericType:Sendable where Scalar:Sendable } extension GenericType:Comparable where Scalar:Comparable { -} -extension GenericType -{ - @inlinable public - var nominal:Scalar? - { - switch self - { - case .nominal(let type): type - case .complex: nil - } - } @inlinable public - func map(_ transform:(Scalar) throws -> T) rethrows -> GenericType + static func < (a:Self, b:Self) -> Bool { - switch self + switch (a.nominal, b.nominal) { - case .nominal(let type): .nominal(try transform(type)) - case .complex(let type): .complex(type) + case (let i?, let j?): (i, a.spelling) < (j, b.spelling) + case (_?, nil): true + case (nil, _?): false + case (nil, nil): a.spelling < b.spelling } } +} +extension GenericType +{ @inlinable public - func flatMap(_ transform:(Scalar) throws -> T?) rethrows -> GenericType? + func map(_ transform:(Scalar) throws -> T?) rethrows -> GenericType { - switch self - { - case .nominal(let type): try transform(type).map { .nominal($0) } - case .complex(let type): .complex(type) - } + .init(spelling: self.spelling, nominal: try self.nominal.map(transform) ?? nil) } } diff --git a/Sources/SymbolGraphParts/Generics/GenericConstraint (ext).swift b/Sources/SymbolGraphParts/Generics/GenericConstraint (ext).swift index e678e83d2..a097f65ce 100644 --- a/Sources/SymbolGraphParts/Generics/GenericConstraint (ext).swift +++ b/Sources/SymbolGraphParts/Generics/GenericConstraint (ext).swift @@ -14,18 +14,9 @@ extension GenericConstraint:JSONObjectDecodable, JSONDecodable where Scalar:JSON public init(json:JSON.ObjectDecoder) throws { - let type:GenericType - if let scalar:Scalar = try json[.rhsPrecise]?.decode() - { - type = .nominal(scalar) - } - else - { - type = .complex(try json[.rhs].decode()) - } - self = .where(try json[.lhs].decode(), is: try json[.kind].decode(as: Kind.self, with: \.operator), - to: type) + to: .init(spelling: try json[.rhs].decode(), + nominal: try json[.rhsPrecise]?.decode())) } } diff --git a/Sources/SymbolGraphTests/Main.Generics.swift b/Sources/SymbolGraphTests/Main.Generics.swift index 68b603dd0..8fafad45c 100644 --- a/Sources/SymbolGraphTests/Main.Generics.swift +++ b/Sources/SymbolGraphTests/Main.Generics.swift @@ -37,8 +37,8 @@ extension Main.Generics:TestBattery { for (name, whom):(String, GenericType) in [ - ("nominal", .nominal(13)), - ("complex", .complex("Dictionary.Index")) + ("nominal", .init(spelling: "", nominal: 13)), + ("complex", .init(spelling: "Dictionary.Index", nominal: nil)) ] { guard let tests:TestGroup = tests / name diff --git a/Sources/SymbolGraphs/Generics/GenericConstraint (ext).swift b/Sources/SymbolGraphs/Generics/GenericConstraint (ext).swift index 8122ff598..c06083b8a 100644 --- a/Sources/SymbolGraphs/Generics/GenericConstraint (ext).swift +++ b/Sources/SymbolGraphs/Generics/GenericConstraint (ext).swift @@ -8,22 +8,27 @@ extension GenericConstraint /// /// The BSON coding schema looks roughly like one of /// - /// `{ G: "0GenericParameterName.AssociatedType", N: 0x1234_5678 }` + /// `{ G: "0GenericParameterName.AssociatedType", C: "Int", N: 0x1234_5678 }` /// /// or /// /// `{ G: "0GenericParameterName.AssociatedType", C: "Array" }` . /// - /// The nominal (`N`) field is usually integer-typed, but its BSON + /// The ``nominal`` (`N`) field is usually integer-typed, but its BSON /// representation is up to the generic ``Scalar`` parameter. /// - /// The complex (`C`) field is always a string. + /// The ``spelling`` (`C`) field is always a string. + /// + /// Prior to 0.9.9, the ``spelling`` was optional. @frozen public enum CodingKey:String, Sendable { case generic = "G" case nominal = "N" - case complex = "C" + case spelling = "C" + + @available(*, deprecated, renamed: "spelling") + static var complex:Self { .spelling } } } extension GenericConstraint:BSONDocumentEncodable, BSONEncodable @@ -41,12 +46,9 @@ extension GenericConstraint:BSONDocumentEncodable, BSONEncodable } bson[.generic] = "\(sigil)\(self.noun)" - - switch self.whom - { - case .nominal(let type): bson[.nominal] = type - case .complex(let description): bson[.complex] = description - } + bson[.nominal] = self.whom.nominal + // For roundtripping pre-0.9.9 BSON. After 1.0, we should encode it unconditionally. + bson[.spelling] = self.whom.spelling.isEmpty ? nil : self.whom.spelling } } extension GenericConstraint:BSONDocumentDecodable, BSONDecodable @@ -72,19 +74,10 @@ extension GenericConstraint:BSONDocumentDecodable, BSONDecodable return (sigil, .init(decoding: $0.bytes.dropFirst(), as: Unicode.UTF8.self)) } - let type:GenericType - // If there is a null value (which is allowed if `Scalar` is an ``Optional`` type), - // we don’t want to attempt to decode from ``CodingKey.complex``. If we do not - // specify the decoded type (`Scalar.self`), the compiler will infer it to be - // `Scalar?`, which will cause us to fall through to the else block! - if let scalar:Scalar = try bson[.nominal]?.decode(to: Scalar.self) - { - type = .nominal(scalar) - } - else - { - type = .complex(try bson[.complex].decode()) - } + let type:GenericType = .init( + // TODO: deoptionalize this after 1.0. + spelling: try bson[.spelling]?.decode() ?? "", + nominal: try bson[.nominal]?.decode()) switch sigil { diff --git a/Sources/SymbolGraphs/SymbolGraphABI.swift b/Sources/SymbolGraphs/SymbolGraphABI.swift index 952e90847..b64fd365d 100644 --- a/Sources/SymbolGraphs/SymbolGraphABI.swift +++ b/Sources/SymbolGraphs/SymbolGraphABI.swift @@ -3,5 +3,5 @@ import SemanticVersions @frozen public enum SymbolGraphABI { - @inlinable public static var version:PatchVersion { .v(0, 9, 8) } + @inlinable public static var version:PatchVersion { .v(0, 9, 9) } } diff --git a/Sources/UnidocLinker/Sema/ConstraintReductionError.swift b/Sources/UnidocLinker/Sema/ConstraintReductionError.swift index d7973fd0f..f12dfe555 100644 --- a/Sources/UnidocLinker/Sema/ConstraintReductionError.swift +++ b/Sources/UnidocLinker/Sema/ConstraintReductionError.swift @@ -4,13 +4,13 @@ import SourceDiagnostics struct ConstraintReductionError:Error, Equatable, Sendable { - let constraints:[[GenericConstraint]] - let minimal:[GenericConstraint] + let constraints:[[GenericConstraint]] + let minimal:[GenericConstraint] let subject:Unidoc.Scalar let `protocol`:Unidoc.Scalar - init(invalid constraints:[[GenericConstraint]], - minimal:[GenericConstraint], + init(invalid constraints:[[GenericConstraint]], + minimal:[GenericConstraint], subject:Unidoc.Scalar, `protocol`:Unidoc.Scalar) { diff --git a/Sources/UnidocLinker/Sema/Unidoc.Conformers.swift b/Sources/UnidocLinker/Sema/Unidoc.Conformers.swift index 91c392ed5..6fdc475f9 100644 --- a/Sources/UnidocLinker/Sema/Unidoc.Conformers.swift +++ b/Sources/UnidocLinker/Sema/Unidoc.Conformers.swift @@ -24,7 +24,7 @@ extension Unidoc.Conformers { mutating func append(conformer type:Unidoc.Scalar, - where constraints:[GenericConstraint]) + where constraints:[GenericConstraint]) { constraints.isEmpty ? self.unconditional.append(type) diff --git a/Sources/UnidocLinker/Sema/Unidoc.ExtensionConditions.swift b/Sources/UnidocLinker/Sema/Unidoc.ExtensionConditions.swift index 90aed2a33..15fbd5626 100644 --- a/Sources/UnidocLinker/Sema/Unidoc.ExtensionConditions.swift +++ b/Sources/UnidocLinker/Sema/Unidoc.ExtensionConditions.swift @@ -5,10 +5,10 @@ extension Unidoc { struct ExtensionConditions:Equatable, Hashable, Sendable { - var constraints:[GenericConstraint] + var constraints:[GenericConstraint] let culture:Int - init(constraints:[GenericConstraint], culture:Int) + init(constraints:[GenericConstraint], culture:Int) { self.constraints = constraints self.culture = culture diff --git a/Sources/UnidocLinker/Sema/Unidoc.Linker.Table.swift b/Sources/UnidocLinker/Sema/Unidoc.Linker.Table.swift index 0493c51cd..1c26cc907 100644 --- a/Sources/UnidocLinker/Sema/Unidoc.Linker.Table.swift +++ b/Sources/UnidocLinker/Sema/Unidoc.Linker.Table.swift @@ -127,7 +127,7 @@ extension Unidoc.Linker.Table return [:] } - let universal:Set> = + let universal:Set> = extendedDecl.signature.generics.constraints.reduce(into: []) { $0.insert($1.map { extendedSnapshot.scalars.decls[$0] }) @@ -139,7 +139,7 @@ extension Unidoc.Linker.Table .init( constraints: $0.conditions.compactMap { - let constraint:GenericConstraint = $0.map + let constraint:GenericConstraint = $0.map { context.current.scalars.decls[$0] } @@ -174,7 +174,15 @@ extension Unidoc.Linker.Table /// ``RawRepresentable`` in the standard library. conditions.constraints.removeAll { - $0 == .where("Self", is: .conformer, to: .nominal(s)) + if case .where("Self", is: .conformer, to: let type) = $0, + case s? = type.nominal + { + true + } + else + { + false + } } } // It’s possible for two locally-disjoint extensions to coalesce diff --git a/Sources/UnidocLinker/Unidoc.Linker.swift b/Sources/UnidocLinker/Unidoc.Linker.swift index 833223aaa..320f844f3 100644 --- a/Sources/UnidocLinker/Unidoc.Linker.swift +++ b/Sources/UnidocLinker/Unidoc.Linker.swift @@ -375,7 +375,7 @@ extension Unidoc.Linker let extancy:Set = conformances.reduce(into: []) { $0.insert($1.culture) } // Group conformances to this protocol by culture. - let segregated:[Int: [[GenericConstraint]]] = conformances.reduce( + let segregated:[Int: [[GenericConstraint]]] = conformances.reduce( into: [:]) { let module:SymbolGraph.Module = self.current.cultures[$1.culture].module @@ -397,14 +397,14 @@ extension Unidoc.Linker // `T:Equatable`, but it also conforms to `Equatable` where // `T:Hashable`, because if `T` is ``Hashable`` then it is also // ``Equatable``. So that conformance is redundant. - let reduced:[Int: [GenericConstraint]] = segregated.mapValues + let reduced:[Int: [GenericConstraint]] = segregated.mapValues { // Swift does not have conditional disjunctions for protocol // conformances. So the most general constraint list must be // (one of) the shortest. - var shortest:[[GenericConstraint]] = [] + var shortest:[[GenericConstraint]] = [] var length:Int = .max - for constraints:[GenericConstraint] in $0 + for constraints:[GenericConstraint] in $0 { if constraints.count < length { @@ -424,18 +424,18 @@ extension Unidoc.Linker return shortest[0] } - let constraints:Set> = .init( + let constraints:Set> = .init( shortest.joined()) - let reduced:Set> = constraints.filter + let reduced:Set> = constraints.filter { switch $0 { - case .where(_, is: .equal, to: _): + case .where(_, is: .equal, to: _): // Same-type constraints are never redundant. return true case .where(let parameter, is: let what, to: let type): - if case .nominal(let type?) = type, + if let type:Unidoc.Scalar = type.nominal, let snapshot:Graph = self[type.package], let local:[Int32] = snapshot.decls[type.citizen]?.decl?.superforms { @@ -446,9 +446,18 @@ extension Unidoc.Linker // constraint is redundant. if let supertype:Unidoc.Scalar = snapshot.scalars.decls[local], supertype != type, - constraints.contains(.where(parameter, - is: what, - to: .nominal(supertype))) + constraints.contains(where: + { + if case .where(parameter, is: what, to: let t) = $0, + case supertype? = t.nominal + { + true + } + else + { + false + } + }) { return false } @@ -466,7 +475,7 @@ extension Unidoc.Linker // contain exactly the same constraints as the reduced set. We don’t // return the set itself, because this implementation does not know // anything about canonical constraint ordering. - let ordered:[[GenericConstraint]] = shortest.filter + let ordered:[[GenericConstraint]] = shortest.filter { $0.allSatisfy(reduced.contains(_:)) } diff --git a/Sources/UnidocLinker/Unidoc.Symbolicator.swift b/Sources/UnidocLinker/Unidoc.Symbolicator.swift index 953d2e865..79cdd8c93 100644 --- a/Sources/UnidocLinker/Unidoc.Symbolicator.swift +++ b/Sources/UnidocLinker/Unidoc.Symbolicator.swift @@ -53,32 +53,39 @@ extension Unidoc.Symbolicator:DiagnosticSymbolicator } extension Unidoc.Symbolicator { - func constraints(_ constraints:[GenericConstraint]) -> String + private + func spell(_ type:GenericType
) -> String + { + guard type.spelling.isEmpty + else + { + return type.spelling + } + + if let id:Address = type.nominal + { + return self[id] + } + else + { + return "" + } + } + + func constraints(_ constraints:[GenericConstraint
]) -> String { constraints.map { switch $0 { - case .where(let parameter, is: .equal, to: .nominal(let type?)): - "\(parameter) == \(self[type])" - - case .where(let parameter, is: .equal, to: .nominal(nil)): - "\(parameter) == " - - case .where(let parameter, is: .equal, to: .complex(let text)): - "\(parameter) == \(text)" - - case .where(let parameter, is: .subclass, to: .nominal(let type?)), - .where(let parameter, is: .conformer, to: .nominal(let type?)): - "\(parameter):\(self[type])" + case .where(let parameter, is: .equal, to: let type): + return "\(parameter) == \(self.spell(type))" - case .where(let parameter, is: .subclass, to: .nominal(nil)), - .where(let parameter, is: .conformer, to: .nominal(nil)): - "\(parameter):" + case .where(let parameter, is: .subclass, to: let type): + fallthrough - case .where(let parameter, is: .subclass, to: .complex(let text)), - .where(let parameter, is: .conformer, to: .complex(let text)): - "\(parameter):\(text)" + case .where(let parameter, is: .conformer, to: let type): + return "\(parameter):\(self.spell(type))" } }.joined(separator: ", ") } diff --git a/Sources/UnidocQueries/Volumes/Mongo.Variable (ext).swift b/Sources/UnidocQueries/Volumes/Mongo.Variable (ext).swift index da66498b0..4f960fa65 100644 --- a/Sources/UnidocQueries/Volumes/Mongo.Variable (ext).swift +++ b/Sources/UnidocQueries/Volumes/Mongo.Variable (ext).swift @@ -5,14 +5,14 @@ import UnidocRecords extension Mongo.Variable { - var constraints:Mongo.List, Mongo.AnyKeyPath> + var constraints:Mongo.List, Mongo.AnyKeyPath> { .init(in: self[.constraints]) } } extension Mongo.Variable { - var constraints:Mongo.List, Mongo.AnyKeyPath> + var constraints:Mongo.List, Mongo.AnyKeyPath> { .init(in: self[.constraints]) } diff --git a/Sources/UnidocQueries/Volumes/Unidoc.LookupAdjacent.Vertices.swift b/Sources/UnidocQueries/Volumes/Unidoc.LookupAdjacent.Vertices.swift index c12622be3..c9a83aad3 100644 --- a/Sources/UnidocQueries/Volumes/Unidoc.LookupAdjacent.Vertices.swift +++ b/Sources/UnidocQueries/Volumes/Unidoc.LookupAdjacent.Vertices.swift @@ -54,7 +54,7 @@ extension Unidoc.LookupAdjacent.Vertices list.expr { - let constraints:Mongo.List, Mongo.AnyKeyPath> = + let constraints:Mongo.List, Mongo.AnyKeyPath> = .init(in: self.vertex / Unidoc.AnyVertex[.signature_generics_constraints]) $0[.map] = constraints.map { $0[.nominal] } diff --git a/Sources/UnidocRecords/Unidoc.EditionSet.swift b/Sources/UnidocRecords/Unidoc.EditionSet.swift index def6cf202..430c912d5 100644 --- a/Sources/UnidocRecords/Unidoc.EditionSet.swift +++ b/Sources/UnidocRecords/Unidoc.EditionSet.swift @@ -63,11 +63,11 @@ extension Unidoc.EditionSet } } mutating - func update(with constraints:[GenericConstraint]) + func update(with constraints:[GenericConstraint]) { - for constraint:GenericConstraint in constraints + for constraint:GenericConstraint in constraints { - self.update(with: constraint.whom.nominal??.edition) + self.update(with: constraint.whom.nominal?.edition) } } mutating diff --git a/Sources/UnidocRecords/Volumes/Groups/Unidoc.ConformingType.swift b/Sources/UnidocRecords/Volumes/Groups/Unidoc.ConformingType.swift index f2361a9bd..80d72f588 100644 --- a/Sources/UnidocRecords/Volumes/Groups/Unidoc.ConformingType.swift +++ b/Sources/UnidocRecords/Volumes/Groups/Unidoc.ConformingType.swift @@ -10,10 +10,10 @@ extension Unidoc public let id:Unidoc.Scalar public - let constraints:[GenericConstraint] + let constraints:[GenericConstraint] @inlinable public - init(id:Unidoc.Scalar, where constraints:[GenericConstraint] = []) + init(id:Unidoc.Scalar, where constraints:[GenericConstraint] = []) { self.id = id self.constraints = constraints diff --git a/Sources/UnidocRecords/Volumes/Groups/Unidoc.ExtensionGroup.swift b/Sources/UnidocRecords/Volumes/Groups/Unidoc.ExtensionGroup.swift index 2c9b2fb45..8938b020b 100644 --- a/Sources/UnidocRecords/Volumes/Groups/Unidoc.ExtensionGroup.swift +++ b/Sources/UnidocRecords/Volumes/Groups/Unidoc.ExtensionGroup.swift @@ -16,7 +16,7 @@ extension Unidoc let id:Unidoc.Group public - let constraints:[GenericConstraint] + let constraints:[GenericConstraint] public let culture:Unidoc.Scalar public @@ -38,7 +38,7 @@ extension Unidoc @inlinable public init(id:Unidoc.Group, - constraints:[GenericConstraint], + constraints:[GenericConstraint], culture:Unidoc.Scalar, scope:Unidoc.Scalar, conformances:[Unidoc.Scalar] = [], diff --git a/Sources/UnidocUI/Cones/Unidoc.Cone.Halo.Generics.swift b/Sources/UnidocUI/Cones/Unidoc.Cone.Halo.Generics.swift index 34e2c6077..a03523b76 100644 --- a/Sources/UnidocUI/Cones/Unidoc.Cone.Halo.Generics.swift +++ b/Sources/UnidocUI/Cones/Unidoc.Cone.Halo.Generics.swift @@ -27,10 +27,10 @@ extension Unidoc.Cone.Halo.Generics /// Returns the number of free generic parameters remaining after applying any same-type /// constraints in the given list. - func count(substituting constraints:[GenericConstraint]) -> Int + func count(substituting constraints:[GenericConstraint]) -> Int { var count:Int = self.parameters.count - for constraint:GenericConstraint in constraints + for constraint:GenericConstraint in constraints { if case .equal = constraint.what, self.parameters.contains(constraint.noun) { diff --git a/Sources/UnidocUI/Cones/Unidoc.Cone.Halo.swift b/Sources/UnidocUI/Cones/Unidoc.Cone.Halo.swift index 7f694d4f5..13ba54136 100644 --- a/Sources/UnidocUI/Cones/Unidoc.Cone.Halo.swift +++ b/Sources/UnidocUI/Cones/Unidoc.Cone.Halo.swift @@ -33,7 +33,7 @@ extension Unidoc.Cone var extensions:[Unidoc.ExtensionGroup] private(set) - var peerConstraints:[GenericConstraint] + var peerConstraints:[GenericConstraint] private(set) var peerList:[Unidoc.Scalar] diff --git a/Sources/UnidocUI/Primitives/Sections/Unidoc.DenseList.Card.swift b/Sources/UnidocUI/Primitives/Sections/Unidoc.DenseList.Card.swift index 0107ab3a9..b7c2c273a 100644 --- a/Sources/UnidocUI/Primitives/Sections/Unidoc.DenseList.Card.swift +++ b/Sources/UnidocUI/Primitives/Sections/Unidoc.DenseList.Card.swift @@ -28,7 +28,7 @@ extension Unidoc.DenseList extension Unidoc.DenseList.Card { init?(_ type:Unidoc.Scalar, - requirements:[GenericConstraint] = [], + requirements:[GenericConstraint] = [], with context:some Unidoc.VertexContext) { guard diff --git a/Sources/UnidocUI/Primitives/Sections/Unidoc.ExtensionSection.swift b/Sources/UnidocUI/Primitives/Sections/Unidoc.ExtensionSection.swift index 72d6fef7a..7871255ab 100644 --- a/Sources/UnidocUI/Primitives/Sections/Unidoc.ExtensionSection.swift +++ b/Sources/UnidocUI/Primitives/Sections/Unidoc.ExtensionSection.swift @@ -35,7 +35,7 @@ extension Unidoc.ExtensionSection var name:String = "\(culture.vertex.module.id)" var first:Bool = true - for requirement:GenericConstraint in group.constraints + for requirement:GenericConstraint in group.constraints { let requirement:Unidoc.WhereClause.Requirement = requirement | context diff --git a/Sources/UnidocUI/Primitives/Sections/Unidoc.WhereClause.swift b/Sources/UnidocUI/Primitives/Sections/Unidoc.WhereClause.swift index 302eb8e44..ebab82f24 100644 --- a/Sources/UnidocUI/Primitives/Sections/Unidoc.WhereClause.swift +++ b/Sources/UnidocUI/Primitives/Sections/Unidoc.WhereClause.swift @@ -10,11 +10,11 @@ extension Unidoc struct WhereClause { private - let requirements:[GenericConstraint] + let requirements:[GenericConstraint] private let context:any VertexContext - init(requirements:[GenericConstraint], context:any VertexContext) + init(requirements:[GenericConstraint], context:any VertexContext) { self.requirements = requirements self.context = context diff --git a/Sources/UnidocUI/operators.swift b/Sources/UnidocUI/operators.swift index 5817f8e3e..a33dc5c02 100644 --- a/Sources/UnidocUI/operators.swift +++ b/Sources/UnidocUI/operators.swift @@ -2,30 +2,27 @@ import HTML import LexicalPaths import Signatures -func | (self:[GenericConstraint], +func | (self:[GenericConstraint], context:some Unidoc.VertexContext) -> Unidoc.WhereClause? { self.isEmpty ? nil : .init(requirements: self, context: context) } -func | (self:GenericConstraint, +func | (self:GenericConstraint, context:some Unidoc.VertexContext) -> Unidoc.WhereClause.Requirement { let whom:HTML.Link - switch self.whom + if self.whom.spelling.isEmpty { - case .complex(let text): - whom = .init(display: .init([], text), target: nil) - - case .nominal(let scalar): - if let scalar:Unidoc.Scalar, + // Backwards compatibility + if let scalar:Unidoc.Scalar = self.whom.nominal, let link:HTML.Link = context.link(decl: scalar) { whom = link } else if - let scalar:Unidoc.Scalar + let scalar:Unidoc.Scalar = self.whom.nominal { whom = .init(display: .init([], "(redacted, \(scalar))"), target: nil) } @@ -34,6 +31,12 @@ func | (self:GenericConstraint, whom = .init(display: .init([], "(redacted)"), target: nil) } } + else + { + whom = .init( + display: .init([], self.whom.spelling), + target: self.whom.nominal.map { context[decl: $0]?.target?.url } ?? nil) + } return .init(parameter: self.noun, is: self.what, to: whom) } From 2ac9248b7fc1652c8d6217fd2613ae1d9ae99809 Mon Sep 17 00:00:00 2001 From: taylorswift Date: Wed, 17 Jul 2024 20:23:19 +0000 Subject: [PATCH 2/2] update test syntax --- Sources/SymbolGraphPartTests/Main.swift | 36 ++++++++++++++++++------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/Sources/SymbolGraphPartTests/Main.swift b/Sources/SymbolGraphPartTests/Main.swift index 13d66a511..a116ed8d1 100644 --- a/Sources/SymbolGraphPartTests/Main.swift +++ b/Sources/SymbolGraphPartTests/Main.swift @@ -381,14 +381,20 @@ enum Main:TestMain, TestBattery ( ["Struct", "internal(_:)"], [ - .where("T", is: .conformer, to: .nominal(.init("s:SQ")!)), - .where("T", is: .conformer, to: .nominal(.init("s:ST")!)), + .where("T", is: .conformer, to: .init( + spelling: "Equatable", + nominal: "sSQ")), + .where("T", is: .conformer, to: .init( + spelling: "Sequence", + nominal: "sST")), ] ), ( ["Protocol", "internal(_:)"], [ - .where("Self.T", is: .conformer, to: .nominal(.init("s:SQ")!)), + .where("Self.T", is: .conformer, to: .init( + spelling: "Equatable", + nominal: "sSQ")), ] ), ] @@ -411,27 +417,39 @@ enum Main:TestMain, TestBattery ( ["Struct"], [ - .where("T", is: .conformer, to: .nominal(.init("s:SQ")!)), - .where("T", is: .conformer, to: .nominal(.init("s:ST")!)), + .where("T", is: .conformer, to: .init( + spelling: "Equatable", + nominal: "sSQ")), + .where("T", is: .conformer, to: .init( + spelling: "Sequence", + nominal: "sST")), ] ), ( ["Struct", "external(_:)"], [ - .where("T", is: .conformer, to: .nominal(.init("s:SQ")!)), - .where("T", is: .conformer, to: .nominal(.init("s:ST")!)), + .where("T", is: .conformer, to: .init( + spelling: "Equatable", + nominal: "sSQ")), + .where("T", is: .conformer, to: .init( + spelling: "Sequence", + nominal: "sST")), ] ), ( ["Protocol"], [ - .where("Self.T", is: .conformer, to: .nominal(.init("s:SQ")!)), + .where("Self.T", is: .conformer, to: .init( + spelling: "Equatable", + nominal: "sSQ")), ] ), ( ["Protocol", "external(_:)"], [ - .where("Self.T", is: .conformer, to: .nominal(.init("s:SQ")!)), + .where("Self.T", is: .conformer, to: .init( + spelling: "Equatable", + nominal: "sSQ")), ] ), ]