Skip to content

Commit

Permalink
Merge pull request #1053 from hylo-lang/generic-captures
Browse files Browse the repository at this point in the history
Avoid over-capturing generic arguments in declaration references
  • Loading branch information
kyouko-taiga authored Oct 3, 2023
2 parents 543b3a0 + fe7a5c1 commit f33e59d
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 8 deletions.
4 changes: 2 additions & 2 deletions Sources/CodeGen/LLVM/Transpilation.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Core
import IR
import Foundation
import IR
import LLVM
import Utils

Expand Down Expand Up @@ -335,7 +335,7 @@ extension LLVM.Module {
private mutating func demandMetatype<T: TypeProtocol>(
of t: T, usedIn m: IR.Module, from ir: IR.Program,
initializedWith initializeInstance: (inout Self, LLVM.GlobalVariable) -> Void
) -> LLVM.GlobalVariable{
) -> LLVM.GlobalVariable {
let globalName = ir.base.mangled(t)
if let g = global(named: globalName) { return g }

Expand Down
7 changes: 4 additions & 3 deletions Sources/Core/CompileTimeValues/GenericArguments.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ public struct GenericArguments {
public init<S: Sequence>(
skolemizing parameters: S, in ast: AST
) where S.Element == GenericParameterDecl.ID {
self.contents = .init(uniqueKeysWithValues: parameters.map { (p) in
(key: p, value: ^GenericTypeParameterType(p, ast: ast))
})
self.contents = .init(
uniqueKeysWithValues: parameters.map { (p) in
(key: p, value: ^GenericTypeParameterType(p, ast: ast))
})
}

/// A collection with the parameters to which arguments are passed.
Expand Down
2 changes: 2 additions & 0 deletions Sources/Core/Program.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ extension Program {
return true
case SubscriptDecl.self:
return ast[SubscriptDecl.ID(decl)!].isStatic
case VarDecl.self:
return isGlobal(varToBinding[VarDecl.ID(decl)!]!)
default:
return false
}
Expand Down
10 changes: 7 additions & 3 deletions Sources/FrontEnd/TypeChecking/TypeChecker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3270,14 +3270,18 @@ struct TypeChecker {
inScopeIntroducing d: AnyDeclID, resolvedIn context: NameResolutionContext?
) -> GenericArguments {
if let a = context?.arguments { return a }

// References to modules can never capture any generic arguments.
if d.kind == ModuleDecl.self { return [:] }
if !mayCaptureGenericParameters(d) { return [:] }

let parameters = accumulatedGenericParameters(in: program[d].scope)
return .init(skolemizing: parameters, in: program.ast)
}

/// Returns `true` if a reference to `d` may capture generic parameters from the surrounding
/// lookup context.
private func mayCaptureGenericParameters(_ d: AnyDeclID) -> Bool {
d.kind.value is GenericScope.Type
}

/// Associates `parameters`, which are introduced by `name`'s declaration, to corresponding
/// values in `arguments` if the two arrays have the same length. Otherwise, returns `nil`,
/// reporting diagnostics to `log`.
Expand Down
17 changes: 17 additions & 0 deletions Sources/FrontEnd/TypedProgram.swift
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,23 @@ public struct TypedProgram {
return result
}

/// Returns the generic parameters captured in the scope of `d` if `d` is callable. Otherwise,
/// returns an empty collection.
public func liftedGenericParameters(of d: AnyDeclID) -> [GenericParameterDecl.ID] {
switch d.kind {
case FunctionDecl.self:
return Array(accumulatedGenericParameters(in: FunctionDecl.ID(d)!))
case InitializerDecl.self:
return Array(accumulatedGenericParameters(in: InitializerDecl.ID(d)!))
case SubscriptImpl.self:
return Array(accumulatedGenericParameters(in: SubscriptImpl.ID(d)!))
case MethodImpl.self:
return Array(accumulatedGenericParameters(in: MethodImpl.ID(d)!))
default:
return []
}
}

/// Returns generic parameters captured by `s` and the scopes semantically containing `s`.
public func accumulatedGenericParameters<T: ScopeID>(
in s: T
Expand Down
30 changes: 30 additions & 0 deletions Sources/IR/Analysis/Module+Depolymorphize.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ extension Module {
_ f: Function.ID, in ir: IR.Program,
for specialization: GenericArguments, in scopeOfUse: AnyScopeID
) -> Function.ID {
// TODO: Avoid monomorphizing non-generic entities (#
// let parameters = ir.base.liftedGenericParameters(of: f)
// if parameters.isEmpty {
// return f
// }
// let specialization = GenericArguments(
// uniqueKeysWithValues: parameters.map({ ($0, specialization[$0]!) }))

let result = demandMonomorphizedDeclaration(of: f, in: ir, for: specialization, in: scopeOfUse)
if self[result].entry != nil {
return result
Expand Down Expand Up @@ -567,3 +575,25 @@ extension Module {
}

}

extension TypedProgram {

/// Returns the generic parameters captured in the scope of `f`.
fileprivate func liftedGenericParameters(of f: Function.ID) -> [GenericParameterDecl.ID] {
switch f.value {
case .lowered(let d):
return liftedGenericParameters(of: d)

case .synthesized(let d):
if let a = BoundGenericType(d.receiver)?.arguments {
return Array(a.keys)
} else {
return []
}

case .existentialized, .monomorphized:
return []
}
}

}

0 comments on commit f33e59d

Please sign in to comment.