diff --git a/include/inference.h b/include/inference.h index b0ea2f6..dcdcf81 100644 --- a/include/inference.h +++ b/include/inference.h @@ -293,7 +293,7 @@ class TypeAnalyzer { TypeAnalyzer(TypeSystem& system, ControlGraph& graph, InferContext& context) : m_system(system), m_graph(graph), m_context(context), m_walker(*this) {} - void run(); + void run(const Type* blockType = 0); private: void processInstruction(const InstructionNode& instruction); @@ -350,6 +350,8 @@ class TypeAnalyzer { bool m_baseRun; bool m_literalBranch; + + const Type* m_blockType; }; } // namespace type diff --git a/src/TypeAnalyzer.cpp b/src/TypeAnalyzer.cpp index 39f7aba..305d95a 100644 --- a/src/TypeAnalyzer.cpp +++ b/src/TypeAnalyzer.cpp @@ -74,10 +74,12 @@ std::string Type::toString(bool subtypesOnly /*= false*/) const { return stream.str(); } -void TypeAnalyzer::run() { +void TypeAnalyzer::run(const Type* blockType /*= 0*/) { if (m_graph.isEmpty()) return; + m_blockType = blockType; + // FIXME For correct inference we need to perform in-width traverse m_baseRun = true; @@ -328,6 +330,17 @@ void TypeAnalyzer::doPushTemporary(const InstructionNode& instruction) { processTau(*tau); m_context[instruction] = tauType; + } else if (m_blockType) { + // Block invocation primitive pass block arguments through creating method's temporaries. + // To simplify inference, we pass their types as context arguments. + + const uint16_t argIndex = TInteger(m_blockType->getSubTypes()[2].getValue()); + const TSmalltalkInstruction::TArgument tempIndex = instruction.getInstruction().getArgument(); + + if (tempIndex >= argIndex) + m_context[instruction] = m_context.getArgument(tempIndex - argIndex); + else + m_context[instruction] = Type(Type::tkPolytype); } } @@ -335,6 +348,7 @@ void TypeAnalyzer::doPushBlock(const InstructionNode& instruction) { if (const PushBlockNode* const pushBlock = instruction.cast()) { TMethod* const origin = pushBlock->getParsedBlock()->getContainer()->getOrigin(); const uint16_t offset = pushBlock->getParsedBlock()->getStartOffset(); + const uint16_t argIndex = instruction.getInstruction().getArgument(); // Block[origin, offset] Type& blockType = m_context[instruction]; @@ -342,6 +356,7 @@ void TypeAnalyzer::doPushBlock(const InstructionNode& instruction) { blockType.set(globals.blockClass, Type::tkMonotype); blockType.addSubType(origin); blockType.addSubType(Type(TInteger(offset))); + blockType.addSubType(Type(TInteger(argIndex))); } } @@ -708,11 +723,11 @@ InferContext* TypeSystem::inferBlock(const Type& block, const Type& arguments) { } type::TypeAnalyzer analyzer(*this, *blockGraph, *inferContext); - analyzer.run(); + analyzer.run(&block); std::printf("%s::%s -> %s, ^%s\n", arguments.toString().c_str(), block.toString().c_str(), inferContext->getReturnType().toString().c_str(), inferContext->getBlockReturnType().toString().c_str()); - return 0; + return inferContext; }