1
1
use crate :: context:: { AnalyzerContext , CallType , FunctionBody } ;
2
2
use crate :: db:: { Analysis , AnalyzerDb } ;
3
3
use crate :: errors:: TypeError ;
4
- use crate :: namespace:: items:: { DepGraph , DepGraphWrapper , DepLocality , FunctionId , Item , TypeDef } ;
4
+ use crate :: namespace:: items:: {
5
+ Class , DepGraph , DepGraphWrapper , DepLocality , FunctionId , Item , TypeDef ,
6
+ } ;
5
7
use crate :: namespace:: scopes:: { BlockScope , BlockScopeType , FunctionScope , ItemScope } ;
6
- use crate :: namespace:: types:: { self , Contract , CtxDecl , SelfDecl , Struct , Type } ;
8
+ use crate :: namespace:: types:: { self , Contract , CtxDecl , Generic , SelfDecl , Struct , Type } ;
7
9
use crate :: traversal:: functions:: traverse_statements;
8
10
use crate :: traversal:: types:: type_desc;
9
11
use fe_common:: diagnostics:: Label ;
@@ -30,6 +32,17 @@ pub fn function_signature(
30
32
let mut names = HashMap :: new ( ) ;
31
33
let mut labels = HashMap :: new ( ) ;
32
34
35
+ if let ( Some ( Class :: Contract ( _) ) , true ) = ( fn_parent, function. is_generic ( db) ) {
36
+ scope. fancy_error (
37
+ "generic function parameters aren't yet supported in contract functions" ,
38
+ vec ! [ Label :: primary(
39
+ function. data( db) . ast. kind. generic_params. span,
40
+ "This can not appear here" ,
41
+ ) ] ,
42
+ vec ! [ "Hint: Struct functions can have generic parameters" . into( ) ] ,
43
+ ) ;
44
+ }
45
+
33
46
let params = def
34
47
. args
35
48
. iter ( )
@@ -55,7 +68,7 @@ pub fn function_signature(
55
68
None
56
69
}
57
70
ast:: FunctionArg :: Regular ( reg) => {
58
- let typ = type_desc ( & mut scope, & reg. typ ) . and_then ( |typ| match typ {
71
+ let typ = resolve_function_param_type ( db , function , & mut scope, & reg. typ ) . and_then ( |typ| match typ {
59
72
typ if typ. has_fixed_size ( ) => Ok ( typ) ,
60
73
_ => Err ( TypeError :: new ( scope. error (
61
74
"function parameter types must have fixed size" ,
@@ -192,6 +205,40 @@ pub fn function_signature(
192
205
}
193
206
}
194
207
208
+ pub fn resolve_function_param_type (
209
+ db : & dyn AnalyzerDb ,
210
+ function : FunctionId ,
211
+ context : & mut dyn AnalyzerContext ,
212
+ desc : & Node < ast:: TypeDesc > ,
213
+ ) -> Result < Type , TypeError > {
214
+ // First check if the param type is a local generic of the function. This won't hold when in the future
215
+ // generics can appear on the contract, struct or module level but it could be good enough for now.
216
+ if let ast:: TypeDesc :: Base { base } = & desc. kind {
217
+ if let Some ( val) = function. generic_param ( db, base) {
218
+ let bounds = match val {
219
+ ast:: GenericParameter :: Unbounded ( _) => vec ! [ ] ,
220
+ ast:: GenericParameter :: Bounded { bound, .. } => match type_desc ( context, & bound) ? {
221
+ Type :: Trait ( trait_ty) => vec ! [ trait_ty. id] ,
222
+ other => {
223
+ context. error (
224
+ & format ! ( "expected trait, found type `{}`" , other) ,
225
+ bound. span ,
226
+ "not a trait" ,
227
+ ) ;
228
+ vec ! [ ]
229
+ }
230
+ } ,
231
+ } ;
232
+
233
+ return Ok ( Type :: Generic ( Generic {
234
+ name : base. clone ( ) ,
235
+ bounds,
236
+ } ) ) ;
237
+ }
238
+ }
239
+ type_desc ( context, desc)
240
+ }
241
+
195
242
/// Gather context information for a function body and check for type errors.
196
243
pub fn function_body ( db : & dyn AnalyzerDb , function : FunctionId ) -> Analysis < Rc < FunctionBody > > {
197
244
let def = & function. data ( db) . ast . kind ;
0 commit comments