mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
SwiftTL: add Resolver.resolveLayeredTypes
Walks layer sections in order, threads a running constructor-name map with last-wins semantics, and snapshots [SumType] at each layer boundary. Constructors appearing only in later layers do not leak into earlier layers' snapshots. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dba8a67bcb
commit
10054efd81
1 changed files with 108 additions and 1 deletions
|
|
@ -199,7 +199,114 @@ enum Resolver {
|
|||
|
||||
return types.values.sorted(by: { $0.name < $1.name })
|
||||
}
|
||||
|
||||
|
||||
static func resolveLayeredTypes(
|
||||
layers: [(layerNumber: Int, constructors: [DescriptionParser.ConstructorDescription])]
|
||||
) throws -> [(layerNumber: Int, types: [SumType])] {
|
||||
// Running state: for each constructor name, the target type name and the raw description.
|
||||
// We keep raw descriptions (not resolved forms) because a later-layer constructor may
|
||||
// introduce new target-type names, and resolveTypeReference needs the final target-type set.
|
||||
var liveConstructors: [QualifiedName: (typeName: QualifiedName, description: DescriptionParser.ConstructorDescription)] = [:]
|
||||
var result: [(layerNumber: Int, types: [SumType])] = []
|
||||
|
||||
for (layerNumber, layerConstructors) in layers {
|
||||
// Apply this layer's constructors to the running map with last-wins semantics.
|
||||
for constructorDescription in layerConstructors {
|
||||
switch constructorDescription.type {
|
||||
case let .type(name):
|
||||
if !name.value[name.value.startIndex].isUppercase {
|
||||
throw ResolutionError(text: "Type constructor \(constructorDescription.name) -> \(name): the resulting type name should begin with a capital letter")
|
||||
}
|
||||
liveConstructors[constructorDescription.name] = (name, constructorDescription)
|
||||
case let .generic(name, argumentType):
|
||||
throw ResolutionError(text: "Type constructor \(constructorDescription.name) can not be used to construct a generic type \(name)<\(argumentType)>")
|
||||
}
|
||||
}
|
||||
|
||||
// Note: a constructor reassigned to a different target type in a later layer is
|
||||
// removed from its old type's constructor set. If that drops the old type to zero
|
||||
// constructors, it vanishes from this snapshot, and any unrelated argument that
|
||||
// still references the old type via boxedType(...) will fail to resolve here.
|
||||
// secret_scheme.tl does not exercise this case (same-name constructors always
|
||||
// target the same type), but the rule applies if a future layered schema does.
|
||||
// Snapshot: group by target type, resolve.
|
||||
var constructedTypes: [QualifiedName: [DescriptionParser.ConstructorDescription]] = [:]
|
||||
var constructorNameToType: [QualifiedName: QualifiedName] = [:]
|
||||
for (ctorName, entry) in liveConstructors {
|
||||
constructedTypes[entry.typeName, default: []].append(entry.description)
|
||||
constructorNameToType[ctorName] = entry.typeName
|
||||
}
|
||||
|
||||
func resolveTypeReference(description: DescriptionParser.TypeReferenceDescription) throws -> TypeReference {
|
||||
switch description {
|
||||
case let .type(name):
|
||||
if let resolvedBuiltinType = resolveBuiltinType(name: name) {
|
||||
return resolvedBuiltinType
|
||||
}
|
||||
if name.value[name.value.startIndex].isUppercase {
|
||||
if let _ = constructedTypes[name] {
|
||||
return .boxedType(name)
|
||||
} else {
|
||||
throw ResolutionError(text: "Unresolved type \(name) in layer \(layerNumber)")
|
||||
}
|
||||
} else {
|
||||
if let typeName = constructorNameToType[name] {
|
||||
return .bareConstructor(typeName: typeName, name: name)
|
||||
} else {
|
||||
throw ResolutionError(text: "Unresolved type constructor \(name) in layer \(layerNumber)")
|
||||
}
|
||||
}
|
||||
case let .generic(name, argumentType):
|
||||
if name == "vector" {
|
||||
return .bareVector(try resolveTypeReference(description: .type(name: argumentType)))
|
||||
} else if name == "Vector" {
|
||||
return .boxedVector(try resolveTypeReference(description: .type(name: argumentType)))
|
||||
} else {
|
||||
throw ResolutionError(text: "Unresolved generic type \(name) in layer \(layerNumber)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func resolveArgument(existingArguments: [Argument], description: DescriptionParser.ArgumentDescription) throws -> Argument {
|
||||
return Argument(
|
||||
name: description.name,
|
||||
type: try resolveTypeReference(description: description.type),
|
||||
condition: try description.condition.flatMap { condition -> Argument.Condition in
|
||||
if !existingArguments.contains(where: { $0.name == condition.fieldName }) {
|
||||
throw ResolutionError(text: "Unresolved conditional field reference to \(condition.fieldName) in layer \(layerNumber)")
|
||||
}
|
||||
return Argument.Condition(fieldName: condition.fieldName, bitIndex: condition.bitIndex)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
var types: [QualifiedName: SumType] = [:]
|
||||
for (typeName, constructorDescriptions) in constructedTypes {
|
||||
let type = SumType(name: typeName)
|
||||
for constructorDescription in constructorDescriptions {
|
||||
var arguments: [Argument] = []
|
||||
for argumentDescription in constructorDescription.arguments {
|
||||
arguments.append(try resolveArgument(existingArguments: arguments, description: argumentDescription))
|
||||
}
|
||||
guard let id = constructorDescription.explicitId else {
|
||||
throw ResolutionError(text: "Constructor \(constructorDescription.name) does not have an id")
|
||||
}
|
||||
type.constructors[constructorDescription.name] = SumType.Constructor(
|
||||
name: constructorDescription.name,
|
||||
id: id,
|
||||
arguments: arguments
|
||||
)
|
||||
}
|
||||
types[type.name] = type
|
||||
}
|
||||
|
||||
let sortedTypes = types.values.sorted(by: { $0.name < $1.name })
|
||||
result.append((layerNumber, sortedTypes))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
static func resolveFunctions(types: [SumType], functionDescriptions: [DescriptionParser.ConstructorDescription]) throws -> [Function] {
|
||||
var functions: [QualifiedName: Function] = [:]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue