1414// You should have received a copy of the GNU General Public License
1515// along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
17+ use clarity_types:: token:: Token ;
1718use clarity_types:: types:: SequenceSubtype ;
1819#[ cfg( test) ]
1920use rstest:: rstest;
@@ -23,6 +24,7 @@ use stacks_common::types::StacksEpochId;
2324
2425use crate :: vm:: analysis:: errors:: { CheckError , CheckErrors , SyntaxBindingError } ;
2526use crate :: vm:: analysis:: mem_type_check as mem_run_analysis;
27+ use crate :: vm:: analysis:: type_checker:: v2_1:: { MAX_FUNCTION_PARAMETERS , MAX_TRAIT_METHODS } ;
2628use crate :: vm:: analysis:: types:: ContractAnalysis ;
2729use crate :: vm:: ast:: build_ast;
2830use crate :: vm:: ast:: errors:: ParseErrors ;
@@ -71,13 +73,13 @@ fn type_check_helper(exp: &str) -> Result<TypeSignature, CheckError> {
7173fn type_check_helper_version (
7274 exp : & str ,
7375 version : ClarityVersion ,
76+ epoch : StacksEpochId ,
7477) -> Result < TypeSignature , CheckError > {
75- mem_run_analysis ( exp, version, StacksEpochId :: latest ( ) )
76- . map ( |( type_sig_opt, _) | type_sig_opt. unwrap ( ) )
78+ mem_run_analysis ( exp, version, epoch) . map ( |( type_sig_opt, _) | type_sig_opt. unwrap ( ) )
7779}
7880
7981fn type_check_helper_v1 ( exp : & str ) -> Result < TypeSignature , CheckError > {
80- type_check_helper_version ( exp, ClarityVersion :: Clarity1 )
82+ type_check_helper_version ( exp, ClarityVersion :: Clarity1 , StacksEpochId :: latest ( ) )
8183}
8284
8385fn buff_type ( size : u32 ) -> TypeSignature {
@@ -286,7 +288,12 @@ fn test_get_block_info() {
286288 expected,
287289 & format!(
288290 "{}" ,
289- type_check_helper_version( good_test, ClarityVersion :: Clarity2 ) . unwrap( )
291+ type_check_helper_version(
292+ good_test,
293+ ClarityVersion :: Clarity2 ,
294+ StacksEpochId :: latest( )
295+ )
296+ . unwrap( )
290297 )
291298 ) ;
292299 }
@@ -295,15 +302,20 @@ fn test_get_block_info() {
295302 expected_v210,
296303 & format!(
297304 "{}" ,
298- type_check_helper_version( good_test_v210, ClarityVersion :: Clarity2 ) . unwrap( )
305+ type_check_helper_version(
306+ good_test_v210,
307+ ClarityVersion :: Clarity2 ,
308+ StacksEpochId :: latest( )
309+ )
310+ . unwrap( )
299311 )
300312 ) ;
301313 }
302314
303315 for ( bad_test, expected) in bad. iter ( ) . zip ( bad_expected. iter ( ) ) {
304316 assert_eq ! (
305317 * expected,
306- * type_check_helper_version( bad_test, ClarityVersion :: Clarity2 )
318+ * type_check_helper_version( bad_test, ClarityVersion :: Clarity2 , StacksEpochId :: latest ( ) )
307319 . unwrap_err( )
308320 . err
309321 ) ;
@@ -354,6 +366,71 @@ fn test_get_burn_block_info() {
354366 }
355367}
356368
369+ #[ apply( test_clarity_versions) ]
370+ fn test_define_functions ( #[ case] version : ClarityVersion , #[ case] epoch : StacksEpochId ) {
371+ let good = [
372+ "(define-private (foo (a uint) (b int)) true)" ,
373+ "(define-public (bar (x (buff 32))) (ok x))" ,
374+ "(define-read-only (baz (p principal)) p)" ,
375+ ] ;
376+
377+ for good_test in good. iter ( ) {
378+ mem_type_check ( good_test) . unwrap ( ) ;
379+ }
380+
381+ // Tests that fail only after epoch 3.3
382+ let bad = [
383+ format ! (
384+ "(define-private (foo {}) true)" ,
385+ ( 0 ..( MAX_FUNCTION_PARAMETERS + 1 ) )
386+ . map( |i| format!( "(param-{} uint)" , i) )
387+ . collect:: <Vec <String >>( )
388+ . join( " " )
389+ ) ,
390+ format ! (
391+ "(define-public (foo {}) (ok true))" ,
392+ ( 0 ..( MAX_FUNCTION_PARAMETERS + 1 ) )
393+ . map( |i| format!( "(param-{} uint)" , i) )
394+ . collect:: <Vec <String >>( )
395+ . join( " " )
396+ ) ,
397+ format ! (
398+ "(define-read-only (foo {}) true)" ,
399+ ( 0 ..( MAX_FUNCTION_PARAMETERS + 1 ) )
400+ . map( |i| format!( "(param-{} uint)" , i) )
401+ . collect:: <Vec <String >>( )
402+ . join( " " )
403+ ) ,
404+ ] ;
405+ let bad_expected = [
406+ CheckErrors :: TooManyFunctionParameters (
407+ MAX_FUNCTION_PARAMETERS + 1 ,
408+ MAX_FUNCTION_PARAMETERS ,
409+ ) ,
410+ CheckErrors :: TooManyFunctionParameters (
411+ MAX_FUNCTION_PARAMETERS + 1 ,
412+ MAX_FUNCTION_PARAMETERS ,
413+ ) ,
414+ CheckErrors :: TooManyFunctionParameters (
415+ MAX_FUNCTION_PARAMETERS + 1 ,
416+ MAX_FUNCTION_PARAMETERS ,
417+ ) ,
418+ ] ;
419+
420+ for ( bad_test, expected) in bad. iter ( ) . zip ( bad_expected. iter ( ) ) {
421+ if epoch. limits_parameter_and_method_count ( ) {
422+ assert_eq ! (
423+ * expected,
424+ * type_check_helper_version( bad_test, version, epoch)
425+ . unwrap_err( )
426+ . err
427+ ) ;
428+ } else {
429+ mem_run_analysis ( bad_test, version, epoch) . unwrap ( ) ;
430+ }
431+ }
432+ }
433+
357434#[ apply( test_clarity_versions) ]
358435fn test_define_trait ( #[ case] version : ClarityVersion , #[ case] epoch : StacksEpochId ) {
359436 let good = [
@@ -371,31 +448,80 @@ fn test_define_trait(#[case] version: ClarityVersion, #[case] epoch: StacksEpoch
371448 "(define-trait trait-1 ((get-1 uint uint)))" ,
372449 "(define-trait trait-1 ((get-1 (uint) (uint))))" ,
373450 "(define-trait trait-1 ((get-1 (response uint uint))))" ,
374- "(define-trait trait-1)" ,
375- "(define-trait)" ,
451+ "(define-trait trait-1 ((get-1 (uint) (response uint uint)) u1))" ,
376452 ] ;
377453 let bad_expected = [
378454 CheckErrors :: InvalidTypeDescription ,
379455 CheckErrors :: DefineTraitBadSignature ,
380456 CheckErrors :: DefineTraitBadSignature ,
381457 CheckErrors :: InvalidTypeDescription ,
458+ CheckErrors :: DefineTraitBadSignature ,
382459 ] ;
383460
384461 for ( bad_test, expected) in bad. iter ( ) . zip ( bad_expected. iter ( ) ) {
385462 assert_eq ! ( * expected, * type_check_helper( bad_test) . unwrap_err( ) . err) ;
386463 }
387464
388- let bad = [ "(define-trait trait-1)" , "(define-trait)" ] ;
465+ // Tests that fail before type-checker
466+ let bad = [
467+ "(define-trait trait-1)" ,
468+ "(define-trait)" ,
469+ "(define-trait trait-1 ((get-1 (uint) (response uint uint)))) u1)" ,
470+ ] ;
389471 let bad_expected = [
390472 ParseErrors :: DefineTraitBadSignature ,
391473 ParseErrors :: DefineTraitBadSignature ,
474+ if epoch == StacksEpochId :: Epoch20 || epoch == StacksEpochId :: Epoch2_05 {
475+ // the pre-2.1 parser returns less instructive errors
476+ ParseErrors :: ClosingParenthesisUnexpected
477+ } else {
478+ ParseErrors :: UnexpectedToken ( Token :: Rparen )
479+ } ,
392480 ] ;
393481
394482 let contract_identifier = QualifiedContractIdentifier :: transient ( ) ;
395483 for ( bad_test, expected) in bad. iter ( ) . zip ( bad_expected. iter ( ) ) {
396484 let res = build_ast ( & contract_identifier, bad_test, & mut ( ) , version, epoch) . unwrap_err ( ) ;
397485 assert_eq ! ( * expected, * res. err) ;
398486 }
487+
488+ // Tests that fail only after epoch 3.3
489+ let bad = [
490+ format ! (
491+ "(define-trait trait-1 ({}))" ,
492+ ( 0 ..( MAX_TRAIT_METHODS + 1 ) )
493+ . map( |i| format!( "(method-{} (uint) (response uint uint))" , i) )
494+ . collect:: <Vec <String >>( )
495+ . join( " " )
496+ ) ,
497+ format ! (
498+ "(define-trait trait-1 ((method ({}) (response uint uint))))" ,
499+ ( 0 ..( MAX_FUNCTION_PARAMETERS + 1 ) )
500+ . map( |i| "uint" . to_string( ) )
501+ . collect:: <Vec <String >>( )
502+ . join( " " )
503+ ) ,
504+ ] ;
505+ let bad_expected = [
506+ CheckErrors :: TraitTooManyMethods ( MAX_TRAIT_METHODS + 1 , MAX_TRAIT_METHODS ) ,
507+ CheckErrors :: TooManyFunctionParameters (
508+ MAX_FUNCTION_PARAMETERS + 1 ,
509+ MAX_FUNCTION_PARAMETERS ,
510+ ) ,
511+ ] ;
512+
513+ for ( bad_test, expected) in bad. iter ( ) . zip ( bad_expected. iter ( ) ) {
514+ if epoch. limits_parameter_and_method_count ( ) {
515+ assert_eq ! (
516+ * expected,
517+ * type_check_helper_version( bad_test, version, epoch)
518+ . unwrap_err( )
519+ . err
520+ ) ;
521+ } else {
522+ mem_run_analysis ( bad_test, version, epoch) . unwrap ( ) ;
523+ }
524+ }
399525}
400526
401527#[ apply( test_clarity_versions) ]
0 commit comments