1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
pub mod analysis_db;
pub mod arithmetic_checker;
pub mod contract_interface_builder;
pub mod errors;
pub mod read_only_checker;
pub mod trait_checker;
pub mod type_checker;
pub mod types;
use crate::types::StacksEpochId;
pub use self::types::{AnalysisPass, ContractAnalysis};
use crate::vm::costs::LimitedCostTracker;
use crate::vm::database::STORE_CONTRACT_SRC_INTERFACE;
use crate::vm::representations::SymbolicExpression;
use crate::vm::types::{QualifiedContractIdentifier, TypeSignature};
use crate::vm::ClarityVersion;
pub use self::analysis_db::AnalysisDatabase;
pub use self::errors::{CheckError, CheckErrors, CheckResult};
use self::arithmetic_checker::ArithmeticOnlyChecker;
use self::contract_interface_builder::build_contract_interface;
use self::read_only_checker::ReadOnlyChecker;
use self::trait_checker::TraitChecker;
use self::type_checker::v2_05::TypeChecker as TypeChecker2_05;
use self::type_checker::v2_1::TypeChecker as TypeChecker2_1;
use crate::vm::ast::build_ast_with_rules;
use crate::vm::ast::ASTRules;
#[cfg(test)]
pub fn type_check(
contract_identifier: &QualifiedContractIdentifier,
expressions: &mut [SymbolicExpression],
analysis_db: &mut AnalysisDatabase,
insert_contract: bool,
epoch: &StacksEpochId,
version: &ClarityVersion,
) -> CheckResult<ContractAnalysis> {
run_analysis(
&contract_identifier,
expressions,
analysis_db,
insert_contract,
LimitedCostTracker::new_free(),
epoch.clone(),
version.clone(),
)
.map_err(|(e, _cost_tracker)| e)
}
pub fn run_analysis(
contract_identifier: &QualifiedContractIdentifier,
expressions: &mut [SymbolicExpression],
analysis_db: &mut AnalysisDatabase,
save_contract: bool,
cost_tracker: LimitedCostTracker,
epoch: StacksEpochId,
version: ClarityVersion,
) -> Result<ContractAnalysis, (CheckError, LimitedCostTracker)> {
let mut contract_analysis = ContractAnalysis::new(
contract_identifier.clone(),
expressions.to_vec(),
cost_tracker,
epoch,
version,
);
let result = analysis_db.execute(|db| {
ReadOnlyChecker::run_pass(&epoch, &mut contract_analysis, db)?;
match epoch {
StacksEpochId::Epoch20 | StacksEpochId::Epoch2_05 => {
TypeChecker2_05::run_pass(&epoch, &mut contract_analysis, db)
}
StacksEpochId::Epoch21 => TypeChecker2_1::run_pass(&epoch, &mut contract_analysis, db),
StacksEpochId::Epoch10 => unreachable!("Epoch 1.0 is not a valid epoch for analysis"),
}?;
TraitChecker::run_pass(&epoch, &mut contract_analysis, db)?;
ArithmeticOnlyChecker::check_contract_cost_eligible(&mut contract_analysis);
if STORE_CONTRACT_SRC_INTERFACE {
let interface = build_contract_interface(&contract_analysis);
contract_analysis.contract_interface = Some(interface);
}
if save_contract {
db.insert_contract(&contract_identifier, &contract_analysis)?;
}
Ok(())
});
match result {
Ok(_) => Ok(contract_analysis),
Err(e) => Err((e, contract_analysis.take_contract_cost_tracker())),
}
}
#[cfg(test)]
mod tests;