Skip to content

Commit 4b2d1f8

Browse files
committed
Merge: phase: Introduction of new hook method
This pr introduces a new hook method in the execution of the `process_nmodule_after_phases` phases. This method makes it possible to analyze each module again after the execution of all phases in order to benefit from the information of the whole program. This method is useful in the context of contracts. Example: ```nit module b redef class A redef fun foo is ensure(result > 2) do return 2 end end var a = new A a.bar ``` ```nit module a class A fun foo: Int do return 1 end fun bar do self.foo end end ``` Actually, when you call the foo property in the bar method, no contract is called, while a postcondition was added by refinement in the `b` module. In fact it was not possible to call the contract face because it was not yet introduced during the analysis of module `a`. It is now possible to re-analyze all the modules to make the redirection once all the information are known. Pull-Request: #2828
2 parents 0c011f8 + 25145c5 commit 4b2d1f8

7 files changed

Lines changed: 22 additions & 17 deletions

File tree

src/compiler/abstract_compiler.nit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import mixin
2626
import counter
2727
import pkgconfig
2828
private import explain_assert_api
29+
import contracts
2930

3031
# Add compiling options
3132
redef class ToolContext

src/compiler/global_compiler.nit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ redef class ToolContext
3030
# option --global
3131
var opt_global = new OptionBool("Use global compilation", "--global")
3232

33-
var global_compiler_phase = new GlobalCompilerPhase(self, null)
33+
var global_compiler_phase = new GlobalCompilerPhase(self, [contracts_phase])
3434

3535
redef init do
3636
super

src/compiler/separate_compiler.nit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ redef class ToolContext
9797
end
9898
end
9999

100-
var separate_compiler_phase = new SeparateCompilerPhase(self, null)
100+
var separate_compiler_phase = new SeparateCompilerPhase(self, [contracts_phase])
101101
end
102102

103103
class SeparateCompilerPhase

src/compiler/separate_erasure_compiler.nit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ redef class ToolContext
4646
end
4747
end
4848

49-
var erasure_compiler_phase = new ErasureCompilerPhase(self, null)
49+
var erasure_compiler_phase = new ErasureCompilerPhase(self, [contracts_phase])
5050
end
5151

5252
class ErasureCompilerPhase

src/contracts.nit

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,33 +35,35 @@ end
3535
private class ContractsPhase
3636
super Phase
3737

38-
# The entry point of the contract phase
39-
# In reality, the contract phase is executed on each module
40-
# FIXME: Actually all method is checked to add method if any contract is inherited
4138
redef fun process_nmodule(nmodule)do
4239
# Check if the contracts are disabled
4340
if toolcontext.opt_no_contract.value then return
4441
nmodule.do_contracts(self.toolcontext)
4542
end
43+
44+
redef fun process_mainmodule(mainmodule: MModule, given_mmodules: SequenceRead[MModule]) do
45+
# Visit all loaded modules `toolcontext.nmodules` to do contract weaving
46+
for nmodule in toolcontext.modelbuilder.nmodules do
47+
nmodule.do_weaving_contracts(self.toolcontext)
48+
end
49+
end
4650
end
4751

4852
redef class AModule
49-
# Compile all contracts
50-
#
51-
# The implementation of the contracts is done in two visits.
52-
#
53-
# - First step, the visitor analyzes and constructs the contracts
54-
# for each class (invariant) and method (expect, ensure).
55-
#
56-
# - Second step the visitor analyzes each `ASendExpr` to see
57-
# if the callsite calls a method with a contract. If this is
58-
# the case the callsite is replaced by another callsite to the contract method.
53+
54+
# Entry point to generate the entire contract infrastructure.
55+
# Once this method is called we must call the `do_weaving_contracts` method (see it for more information).
5956
fun do_contracts(toolcontext: ToolContext) do
6057
var ast_builder = new ASTBuilder(mmodule.as(not null))
6158
#
6259
var contract_visitor = new ContractsVisitor(toolcontext, toolcontext.modelbuilder.identified_modules.first, self, ast_builder)
6360
contract_visitor.enter_visit(self)
64-
#
61+
end
62+
63+
# Entry point to execute the weaving in order to redirect the calls to the contract sides if it's needed.
64+
fun do_weaving_contracts(toolcontext: ToolContext)
65+
do
66+
var ast_builder = new ASTBuilder(mmodule.as(not null))
6567
var callsite_visitor = new CallSiteVisitor(toolcontext, ast_builder)
6668
callsite_visitor.enter_visit(self)
6769
end

src/nit.nit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ else
7575
end
7676

7777
modelbuilder.run_phases
78+
toolcontext.run_global_phases(modelbuilder.parsed_modules)
7879

7980
if toolcontext.opt_only_metamodel.value then toolcontext.quit
8081

tests/sav/nit_args9.res

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
test_keep_going.nit:44,18--21: Error: method `fail` does not exists in `Sys`.
1717
var a = new Sys.fail
1818
^
19+
Errors: 6. Warnings: 0.
1920
1
2021
2
2122
3

0 commit comments

Comments
 (0)