@@ -2,27 +2,27 @@ use crate::context::{AnalyzerContext, CallType, FunctionBody};
2
2
use crate :: db:: { Analysis , AnalyzerDb } ;
3
3
use crate :: errors:: TypeError ;
4
4
use crate :: namespace:: items:: {
5
- Class , DepGraph , DepGraphWrapper , DepLocality , FunctionId , Item , TypeDef ,
5
+ Class , DepGraph , DepGraphWrapper , DepLocality , FunctionId , FunctionSigId , Item , TypeDef ,
6
6
} ;
7
7
use crate :: namespace:: scopes:: { BlockScope , BlockScopeType , FunctionScope , ItemScope } ;
8
8
use crate :: namespace:: types:: { self , Contract , CtxDecl , Generic , SelfDecl , Struct , Type } ;
9
9
use crate :: traversal:: functions:: traverse_statements;
10
10
use crate :: traversal:: types:: type_desc;
11
11
use fe_common:: diagnostics:: Label ;
12
- use fe_parser:: ast;
12
+ use fe_parser:: ast:: { self , GenericParameter } ;
13
13
use fe_parser:: node:: Node ;
14
14
use if_chain:: if_chain;
15
+ use smol_str:: SmolStr ;
15
16
use std:: collections:: HashMap ;
16
17
use std:: rc:: Rc ;
17
18
18
19
/// Gather context information for a function definition and check for type
19
20
/// errors. Does not inspect the function body.
20
21
pub fn function_signature (
21
22
db : & dyn AnalyzerDb ,
22
- function : FunctionId ,
23
+ function : FunctionSigId ,
23
24
) -> Analysis < Rc < types:: FunctionSignature > > {
24
- let node = & function. data ( db) . ast ;
25
- let def = & node. kind ;
25
+ let def = & function. data ( db) . ast ;
26
26
27
27
let mut scope = ItemScope :: new ( db, function. module ( db) ) ;
28
28
let fn_parent = function. class ( db) ;
@@ -32,9 +32,27 @@ pub fn function_signature(
32
32
let mut names = HashMap :: new ( ) ;
33
33
let mut labels = HashMap :: new ( ) ;
34
34
35
- if let ( Some ( Class :: Contract ( _) ) , true ) = ( fn_parent, function. is_generic ( db) ) {
35
+ function. data ( db) . ast . kind . generic_params . kind . iter ( ) . fold (
36
+ HashMap :: < SmolStr , Node < _ > > :: new ( ) ,
37
+ |mut accum, param| {
38
+ if let Some ( previous) = accum. get ( & param. name ( ) ) {
39
+ scope. duplicate_name_error (
40
+ "duplicate generic parameter" ,
41
+ & param. name ( ) ,
42
+ previous. span ,
43
+ param. name_node ( ) . span ,
44
+ ) ;
45
+ } else {
46
+ accum. insert ( param. name ( ) , param. name_node ( ) ) ;
47
+ } ;
48
+
49
+ accum
50
+ } ,
51
+ ) ;
52
+
53
+ if !matches ! ( fn_parent, Some ( Class :: Struct ( _) ) ) && function. is_generic ( db) {
36
54
scope. fancy_error (
37
- "generic function parameters aren't yet supported in contract functions" ,
55
+ "generic function parameters aren't yet supported outside of struct functions" ,
38
56
vec ! [ Label :: primary(
39
57
function. data( db) . ast. kind. generic_params. span,
40
58
"This can not appear here" ,
@@ -43,7 +61,26 @@ pub fn function_signature(
43
61
) ;
44
62
}
45
63
64
+ if function. is_generic ( db) {
65
+ for param in function. data ( db) . ast . kind . generic_params . kind . iter ( ) {
66
+ if let GenericParameter :: Unbounded ( val) = param {
67
+ scope. fancy_error (
68
+ "unbounded generic parameters aren't yet supported" ,
69
+ vec ! [ Label :: primary(
70
+ val. span,
71
+ format!( "`{}` needs to be bound by some trait" , val. kind) ,
72
+ ) ] ,
73
+ vec ! [ format!(
74
+ "Hint: Change `{}` to `{}: SomeTrait`" ,
75
+ val. kind, val. kind
76
+ ) ] ,
77
+ ) ;
78
+ }
79
+ }
80
+ }
81
+
46
82
let params = def
83
+ . kind
47
84
. args
48
85
. iter ( )
49
86
. enumerate ( )
@@ -73,7 +110,7 @@ pub fn function_signature(
73
110
_ => Err ( TypeError :: new ( scope. error (
74
111
"function parameter types must have fixed size" ,
75
112
reg. typ . span ,
76
- "`Map ` type can't be used as a function parameter",
113
+ & format ! ( "`{} ` type can't be used as a function parameter", typ . name ( ) ) ,
77
114
) ) ) ,
78
115
} ) ;
79
116
@@ -114,9 +151,9 @@ pub fn function_signature(
114
151
if label. kind != "_" ;
115
152
if let Some ( dup_idx) = labels. get( & label. kind) ;
116
153
then {
117
- let dup_arg: & Node <ast:: FunctionArg > = & def. args[ * dup_idx] ;
154
+ let dup_arg: & Node <ast:: FunctionArg > = & def. kind . args[ * dup_idx] ;
118
155
scope. fancy_error(
119
- & format!( "duplicate parameter labels in function `{}`" , def. name. kind) ,
156
+ & format!( "duplicate parameter labels in function `{}`" , def. kind . name. kind) ,
120
157
vec![
121
158
Label :: primary( dup_arg. span, "the label `{}` was first used here" ) ,
122
159
Label :: primary( label. span, "label `{}` used again here" ) ,
@@ -138,9 +175,9 @@ pub fn function_signature(
138
175
) ;
139
176
None
140
177
} else if let Some ( dup_idx) = names. get ( & reg. name . kind ) {
141
- let dup_arg: & Node < ast:: FunctionArg > = & def. args [ * dup_idx] ;
178
+ let dup_arg: & Node < ast:: FunctionArg > = & def. kind . args [ * dup_idx] ;
142
179
scope. duplicate_name_error (
143
- & format ! ( "duplicate parameter names in function `{}`" , def . name. kind ) ,
180
+ & format ! ( "duplicate parameter names in function `{}`" , function . name( db ) ) ,
144
181
& reg. name . kind ,
145
182
dup_arg. span ,
146
183
arg. span ,
@@ -159,10 +196,11 @@ pub fn function_signature(
159
196
. collect ( ) ;
160
197
161
198
let return_type = def
199
+ . kind
162
200
. return_type
163
201
. as_ref ( )
164
202
. map ( |type_node| {
165
- let fn_name = & def . name . kind ;
203
+ let fn_name = & function . name ( db ) ;
166
204
if fn_name == "__init__" || fn_name == "__call__" {
167
205
// `__init__` and `__call__` must not return any type other than `()`.
168
206
if type_node. kind != ast:: TypeDesc :: Unit {
@@ -207,7 +245,7 @@ pub fn function_signature(
207
245
208
246
pub fn resolve_function_param_type (
209
247
db : & dyn AnalyzerDb ,
210
- function : FunctionId ,
248
+ function : FunctionSigId ,
211
249
context : & mut dyn AnalyzerContext ,
212
250
desc : & Node < ast:: TypeDesc > ,
213
251
) -> Result < Type , TypeError > {
@@ -254,11 +292,11 @@ pub fn function_body(db: &dyn AnalyzerDb, function: FunctionId) -> Analysis<Rc<F
254
292
"function body is missing a return or revert statement" ,
255
293
vec ! [
256
294
Label :: primary(
257
- def . name . span ,
295
+ function . name_span ( db ) ,
258
296
"all paths of this function must `return` or `revert`" ,
259
297
) ,
260
298
Label :: secondary(
261
- def. return_type. as_ref( ) . unwrap( ) . span,
299
+ def. sig . kind . return_type. as_ref( ) . unwrap( ) . span,
262
300
format!( "expected function to return `{}`" , return_type) ,
263
301
) ,
264
302
] ,
@@ -362,6 +400,13 @@ pub fn function_dependency_graph(db: &dyn AnalyzerDb, function: FunctionId) -> D
362
400
directs. push ( ( root, class. as_item ( ) , DepLocality :: Local ) ) ;
363
401
directs. push ( ( root, Item :: Function ( * method) , DepLocality :: Local ) ) ;
364
402
}
403
+ CallType :: TraitValueMethod { trait_id, .. } => {
404
+ directs. push ( (
405
+ root,
406
+ Item :: Type ( TypeDef :: Trait ( * trait_id) ) ,
407
+ DepLocality :: Local ,
408
+ ) ) ;
409
+ }
365
410
CallType :: External { contract, function } => {
366
411
directs. push ( ( root, Item :: Function ( * function) , DepLocality :: External ) ) ;
367
412
// Probably redundant:
0 commit comments