Skip to content

[lldb][NFC] Check if can eval expr without binding earlier #5791

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ CompilerType SwiftExpressionParser::ResolveVariable(
return var_type;
}

static lldb::VariableSP FindSelfVariable(Block *block) {
lldb::VariableSP SwiftExpressionParser::FindSelfVariable(Block *block) {
if (!block)
return {};

Expand Down Expand Up @@ -529,7 +529,7 @@ static void AddRequiredAliases(Block *block, lldb::StackFrameSP &stack_frame_sp,
LLDB_SCOPED_TIMER();

// First emit the typealias for "$__lldb_context".
lldb::VariableSP self_var_sp = FindSelfVariable(block);
lldb::VariableSP self_var_sp = SwiftExpressionParser::FindSelfVariable(block);

if (!self_var_sp)
return;
Expand Down Expand Up @@ -1067,91 +1067,6 @@ struct ParsedExpression {

} // namespace

/// Check if we can evaluate the expression as generic.
/// Currently, evaluating expression as a generic has several limitations:
/// - Only self will be evaluated with unbound generics.
/// - The Self type can only have one generic parameter.
/// - The Self type has to be the outermost type with unbound generics.
static bool CanEvaluateExpressionAsGeneric(
llvm::ArrayRef<SwiftASTManipulator::VariableInfo> variables, Block *block,
StackFrame &stack_frame) {
// First, find the compiler type of self with the generic parameters not
// bound.
auto self_var = FindSelfVariable(block);
if (!self_var)
return false;

lldb::ValueObjectSP self_valobj =
stack_frame.GetValueObjectForFrameVariable(self_var,
lldb::eNoDynamicValues);
if (!self_valobj)
return false;

auto self_type = self_valobj->GetCompilerType();
if (!self_type)
return false;

auto *ts = self_type.GetTypeSystem()
.dyn_cast_or_null<TypeSystemSwift>()
->GetSwiftASTContext();

if (!ts)
return false;

auto swift_type = ts->GetSwiftType(self_type);
if (!swift_type)
return false;

auto *decl = swift_type->getAnyGeneric();
if (!decl)
return false;


auto *env = decl->getGenericEnvironment();
if (!env)
return false;
auto params = env->getGenericParams();

// If there aren't any generic parameters we can't evaluate the expression as
// generic.
if (params.empty())
return false;

auto *first_param = params[0];
// Currently we only support evaluating self as generic if the generic
// parameter is the first one.
if (first_param->getDepth() != 0 || first_param->getIndex() != 0)
return false;

bool contains_0_0 = false;
bool contains_other_0_depth_params = false;
for (auto *pair : params) {
if (pair->getDepth() == 0) {
if (pair->getIndex() == 0)
contains_0_0 = true;
else
contains_other_0_depth_params = true;
}
}

// We only allow generic evaluation when the Self type contains the outermost
// generic parameter.
if (!contains_0_0)
return false;

// We only allow the Self type to have one generic parameter.
if (contains_other_0_depth_params)
return false;

// Now, check that we do have the metadata pointer as a local variable.
for (auto &variable : variables) {
if (variable.GetName().str() == "$τ_0_0")
return true;
}
// Couldn't find the metadata pointer, so can't evaluate as generic.
return false;
}

/// Attempt to parse an expression and import all the Swift modules
/// the expression and its context depend on.
static llvm::Expected<ParsedExpression> ParseAndImport(
Expand Down Expand Up @@ -1363,13 +1278,6 @@ static llvm::Expected<ParsedExpression> ParseAndImport(
ResolveSpecialNames(sc, exe_scope, swift_ast_context, special_names,
local_variables);

if (options.GetBindGenericTypes() == lldb::eDontBind &&
!CanEvaluateExpressionAsGeneric(local_variables, sc.block,
*stack_frame_sp.get()))
return make_error<StringError>(
inconvertibleErrorCode(),
"Could not evaluate the expression without binding generic types.");

if (!code_manipulator->AddExternalVariables(local_variables))
return make_error<StringError>(inconvertibleErrorCode(),
"Could not add external variables.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ class SwiftExpressionParser : public ExpressionParser {
SwiftLanguageRuntime *runtime, lldb::DynamicValueType use_dynamic,
lldb::BindGenericTypes bind_generic_types);

static lldb::VariableSP FindSelfVariable(Block *block);

//------------------------------------------------------------------
/// Information about each variable provided to the expression, so
/// that we can generate proper accesses in the SIL.
Expand Down
109 changes: 104 additions & 5 deletions lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@
//
//===----------------------------------------------------------------------===//

#include "swift/AST/ASTContext.h"
#include "swift/Demangling/Demangler.h"
#include <stdio.h>
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif

#include "SwiftASTManipulator.h""
#include "SwiftASTManipulator.h"
#include "SwiftExpressionParser.h"
#include "SwiftExpressionSourceCode.h"
#include "SwiftREPLMaterializer.h"
#include "SwiftASTManipulator.h"

#include "Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h"
#include "lldb/Core/Module.h"
Expand All @@ -40,6 +39,10 @@

#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "swift/AST/ASTContext.h"
#include "swift/Demangling/Demangler.h"
#include "swift/AST/GenericEnvironment.h"


#include <cstdlib>
#include <map>
Expand Down Expand Up @@ -451,14 +454,99 @@ GetPersistentState(Target *target, ExecutionContext &exe_ctx) {
return target->GetSwiftPersistentExpressionState(*exe_scope);
}

/// Check if we can evaluate the expression as generic.
/// Currently, evaluating expression as a generic has several limitations:
/// - Only self will be evaluated with unbound generics.
/// - The Self type can only have one generic parameter.
/// - The Self type has to be the outermost type with unbound generics.
static bool CanEvaluateExpressionWithoutBindingGenericParams(
const llvm::SmallVectorImpl<SwiftASTManipulator::VariableInfo>
&variables,
Block *block, StackFrame &stack_frame) {
// First, find the compiler type of self with the generic parameters not
// bound.
auto self_var = SwiftExpressionParser::FindSelfVariable(block);
if (!self_var)
return false;

lldb::ValueObjectSP self_valobj =
stack_frame.GetValueObjectForFrameVariable(self_var,
lldb::eNoDynamicValues);
if (!self_valobj)
return false;

auto self_type = self_valobj->GetCompilerType();
if (!self_type)
return false;

auto *ts = self_type.GetTypeSystem()
.dyn_cast_or_null<TypeSystemSwift>()
->GetSwiftASTContext();

if (!ts)
return false;

auto swift_type = ts->GetSwiftType(self_type);
if (!swift_type)
return false;

auto *decl = swift_type->getAnyGeneric();
if (!decl)
return false;


auto *env = decl->getGenericEnvironment();
if (!env)
return false;
auto params = env->getGenericParams();

// If there aren't any generic parameters we can't evaluate the expression as
// generic.
if (params.empty())
return false;

auto *first_param = params[0];
// Currently we only support evaluating self as generic if the generic
// parameter is the first one.
if (first_param->getDepth() != 0 || first_param->getIndex() != 0)
return false;

bool contains_0_0 = false;
bool contains_other_0_depth_params = false;
for (auto *pair : params) {
if (pair->getDepth() == 0) {
if (pair->getIndex() == 0)
contains_0_0 = true;
else
contains_other_0_depth_params = true;
}
}

// We only allow generic evaluation when the Self type contains the outermost
// generic parameter.
if (!contains_0_0)
return false;

// We only allow the Self type to have one generic parameter.
if (contains_other_0_depth_params)
return false;

// Now, check that we do have the metadata pointer as a local variable.
for (auto &variable : variables) {
if (variable.GetName().str() == "$τ_0_0")
return true;
}
// Couldn't find the metadata pointer, so can't evaluate as generic.
return false;
}

SwiftExpressionParser::ParseResult
SwiftUserExpression::GetTextAndSetExpressionParser(
DiagnosticManager &diagnostic_manager,
std::unique_ptr<SwiftExpressionSourceCode> &source_code,
ExecutionContext &exe_ctx, ExecutionContextScope *exe_scope) {
using ParseResult = SwiftExpressionParser::ParseResult;
Log *log = GetLog(LLDBLog::Expressions);
uint32_t first_body_line = 0;

lldb::TargetSP target_sp;
SymbolContext sc;
Expand All @@ -468,9 +556,10 @@ SwiftUserExpression::GetTextAndSetExpressionParser(
stack_frame = exe_scope->CalculateStackFrame();

if (stack_frame) {
sc = stack_frame->GetSymbolContext(lldb::eSymbolContextEverything);
sc = stack_frame->GetSymbolContext(lldb::eSymbolContextEverything);
}
}

llvm::SmallVector<SwiftASTManipulator::VariableInfo> local_variables;

if (!RegisterAllVariables(sc, stack_frame, *m_swift_ast_ctx, local_variables,
Expand All @@ -483,6 +572,16 @@ SwiftUserExpression::GetTextAndSetExpressionParser(
return ParseResult::retry_no_bind_generic_params;
}

if (m_options.GetBindGenericTypes() == lldb::eDontBind &&
!CanEvaluateExpressionWithoutBindingGenericParams(
local_variables, sc.block, *stack_frame.get())) {
diagnostic_manager.PutString(
eDiagnosticSeverityError,
"Could not evaluate the expression without binding generic types.");
return ParseResult::unrecoverable_error;
}

uint32_t first_body_line = 0;
if (!source_code->GetText(m_transformed_text, m_options.GetLanguage(),
m_needs_object_ptr, m_in_static_method, m_is_class,
m_is_weak_self, m_options, exe_ctx,
Expand Down