From ee6a78a71df25f2584b02e7cbce96cfd6b4019e0 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Wed, 14 Dec 2022 10:05:22 -0800 Subject: [PATCH] [lldb][NFC] Check if can eval expr without binding earlier Move the check that we can evaluate the expression without binding the generic paramaters from SwiftExpressionParser (after we generate an AST from the user's expression) to SwiftUserExpression, before we get the text binding the user's expression. --- .../Swift/SwiftExpressionParser.cpp | 96 +-------------- .../Swift/SwiftExpressionParser.h | 2 + .../Swift/SwiftUserExpression.cpp | 109 +++++++++++++++++- 3 files changed, 108 insertions(+), 99 deletions(-) diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp index b8fcdbd972d12..7e75fd3a9887e 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp @@ -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 {}; @@ -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; @@ -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 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() - ->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 ParseAndImport( @@ -1363,13 +1278,6 @@ static llvm::Expected 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( - inconvertibleErrorCode(), - "Could not evaluate the expression without binding generic types."); - if (!code_manipulator->AddExternalVariables(local_variables)) return make_error(inconvertibleErrorCode(), "Could not add external variables."); diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.h b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.h index ed57748843295..0be2a47f1c434 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.h +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.h @@ -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. diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp index 217b8a85a8843..75fd9d80d644d 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp @@ -10,17 +10,16 @@ // //===----------------------------------------------------------------------===// -#include "swift/AST/ASTContext.h" -#include "swift/Demangling/Demangler.h" #include #if HAVE_SYS_TYPES_H #include #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" @@ -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 #include @@ -451,6 +454,92 @@ 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 + &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() + ->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, @@ -458,7 +547,6 @@ SwiftUserExpression::GetTextAndSetExpressionParser( 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; @@ -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 local_variables; if (!RegisterAllVariables(sc, stack_frame, *m_swift_ast_ctx, local_variables, @@ -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,