Files
swift-mirror/SwiftCompilerSources/Sources/Optimizer/ModulePasses/DiagnoseUnknownConstValues.swift
Erik Eckstein 1c9a7cd562 SwiftCompilerSources: refactor DiagnosticEngine
* move it from the SIL to the AST module (where it belongs)
* change the signature of `diagnose` from `diagnose(location, .some_error)` to `diagnose(.some_error, at: location)`
* add an overload to allow passing a `SIL.Location` directly to `diagnose`
* add a `Diagnostic : Error` utility struct which allows throwing a `Diagnostic`
2025-04-18 06:58:38 +02:00

104 lines
3.8 KiB
Swift

//===--------- DiagnoseUnknownConstValues.swift --------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import SIL
import AST
/// Performs mandatory diagnostic pass for emitting errors for '@const' values which the compiler was not able to
/// simplify/interpret/reduce to a symbolic value.
///
let diagnoseUnknownConstValues = ModulePass(name: "diagnose-unknown-const-values") {
(moduleContext: ModulePassContext) in
var constExprEvaluator: ConstExpressionEvaluator = .init()
defer { constExprEvaluator.deinitialize() }
// Verify all const globals to be initialized with compile-time known values
verifyGlobals(moduleContext)
// Verify @const lets appearing as local variables
verifyLocals(constExprEvaluator: &constExprEvaluator,
moduleContext)
// For each function call, ensure arguments to @const parameters are all compile-time known values
verifyCallArguments(constExprEvaluator: &constExprEvaluator,
moduleContext)
// For each `@const` function, ensure it is fully evaluable/interpretable at compile time
verifyFunctions(moduleContext)
}
private func verifyGlobals(_ context: ModulePassContext) {
for gv in context.globalVariables where gv.isConst {
if gv.staticInitValue == nil {
context.diagnosticEngine.diagnose(.require_const_initializer_for_const,
at: gv.varDecl?.location.sourceLoc)
}
}
}
private func verifyLocals(constExprEvaluator: inout ConstExpressionEvaluator,
_ context: ModulePassContext) {
for f in context.functions {
for i in f.instructions {
if let dbi = i as? DebugValueInst {
verifyLocal(debugValueInst: dbi, constExprState: &constExprEvaluator, in: context)
}
}
}
}
private func verifyLocal(debugValueInst: DebugValueInst,
constExprState: inout ConstExpressionEvaluator,
in context: ModulePassContext) {
guard let localVarDecl = debugValueInst.varDecl,
!(localVarDecl is ParamDecl),
localVarDecl.isConst else {
return
}
if !constExprState.isConstantValue(debugValueInst.operand.value) {
context.diagnosticEngine.diagnose(.require_const_initializer_for_const,
at: debugValueInst.location)
}
}
private func verifyCallArguments(constExprEvaluator: inout ConstExpressionEvaluator,
_ context: ModulePassContext) {
for f in context.functions {
for i in f.instructions {
// TODO: Consider closures (partial_apply)
if let apply = i as? FullApplySite {
verifyCallArguments(apply: apply, constExprState: &constExprEvaluator, in: context)
}
}
}
}
private func verifyCallArguments(apply: FullApplySite,
constExprState: inout ConstExpressionEvaluator,
in context: ModulePassContext) {
guard let calleeFn = apply.referencedFunction else {
return
}
for (paramIdx, param) in calleeFn.convention.parameters.enumerated() where param.hasOption(.const) {
let matchingOperand = apply.parameterOperands[paramIdx]
if !constExprState.isConstantValue(matchingOperand.value) {
context.diagnosticEngine.diagnose(.require_const_arg_for_parameter,
at: apply.location)
}
}
}
private func verifyFunctions(_ context: ModulePassContext) {
// TODO: Implement
}